{"version":3,"sources":["webpack:///./node_modules/@videojs/http-streaming/dist/videojs-http-streaming.es.js"],"names":["resolveUrl","resolveManifestRedirect","url","req","responseURL","logger","source","log","debug","bind","merge","args","context","obj","fn","mergeOptions","apply","createTimeRanges","time","bufferedRangesToString","buffered","length","bufferedRangesStr","i","start","end","TIME_FUDGE_FACTOR","SAFE_TIME_DELTA","filterRanges","timeRanges","predicate","results","push","findRange","findNextRange","findGaps","ranges","bufferIntersection","bufferA","bufferB","arity","extents","count","type","sort","a","b","printableRange","range","strArr","join","timeUntilRebuffer","currentTime","playbackRate","bufferedEnd","timeRangesToArray","timeRangesList","isRangeDifferent","lastBufferedEnd","timeAheadOf","startTime","segmentDurationWithParts","playlist","segment","preload","duration","result","parts","forEach","p","preloadHints","partTargetDuration","getPartsAndSegments","segments","reduce","acc","si","part","pi","segmentIndex","partIndex","getLastParts","media","lastSegment","getKnownPartCount","preloadSegment","partCount","hint","liveEdgeDelay","main","endList","suggestedPresentationDelay","hasParts","serverControl","partHoldBack","holdBack","targetDuration","backwardDuration","endSequence","mediaSequence","precise","forwardDuration","intervalDuration","expired","backward","forward","totalDuration","Infinity","sumDurations","defaultDuration","durationList","startIndex","endIndex","durations","Math","min","playlistEnd","useSafeLiveEnd","liveEdgePadding","lastSegmentEndTime","max","seekable","seekableStart","seekableEnd","getMediaInfoForTime","startingSegmentIndex","startingPartIndex","exactManifestTimings","partsAndSegments","partAndSegment","canUseFudgeFactor","isExactlyAtTheEnd","isExtremelyCloseToTheEnd","isExcluded","excludeUntil","Date","now","isIncompatible","isEnabled","excluded","disabled","isDisabled","isAes","key","hasAttribute","attr","attributes","estimateSegmentRequestTime","segmentDuration","bandwidth","bytesReceived","NaN","size","BANDWIDTH","isLowestEnabledRendition","playlists","currentBandwidth","Number","MAX_VALUE","filter","playlistMatch","id","resolvedUri","uri","someAudioVariant","callback","AUDIO","mediaGroups","found","groupName","label","isAudioOnly","variant","CODECS","split","every","c","Playlist","createPlaylistID","index","groupID","group","parseManifest","onwarn","oninfo","manifestString","customTagParsers","customTagMappers","llhls","parser","on","customParser","addParser","mapper","addTagMapper","manifest","k","hasOwnProperty","s","message","error","forEachMediaGroup","mediaType","groupKey","labelKey","mediaProperties","setupMediaPlaylist","playlistErrors_","setupMediaPlaylists","warn","resolveMediaGroupUris","properties","mainForMedia","location","href","addPropertiesToMain","createGroupID","phonyUri","audioOnlyMain","groupId","DateRangesStorage","this","offset_","pendingDateRanges_","Map","processedDateRanges_","firstSegment","undefined","programDateTime","dateRanges","dateRange","startDate","getTime","trimProcessedDateRanges_","map","pendingDateRange","set","delete","dateRangeClasses","dateRangesToProcess","has","processDateRange","class","classListIndex","classList","endDate","endTime","endOnNext","plannedDuration","copy","QUOTA_EXCEEDED_ERR","getStreamingNetworkErrorMetadata","requestType","request","parseFailure","isBadStatus","status","isFailure","errorMetadata","isBadStatusOrParseFailure","errorType","Error","NetworkRequestFailed","aborted","NetworkRequestAborted","timedout","erroType","NetworkRequestTimeout","NetworkBodyParserFailed","NetworkBadStatus","headers","EventTarget","EventTarget$1","addLLHLSQueryDirectives","parameters","canBlockReload","nextMSN","nextPart","_HLS_part","_HLS_msn","canSkipUntil","_HLS_skip","canSkipDateranges","Object","keys","parsedUri","URL","name","searchParams","toString","updateSegment","skipped","updateSegments","original","update","offset","oldSegments","slice","newSegments","currentMap","newIndex","oldSegment","newSegment","resolveSegmentUris","baseUri","getAllSegments","isPlaylistUnchanged","updateMain$1","newMedia","unchangedCheck","oldMedia","mergedPlaylist","skip","skippedSegments","unshift","refreshDelay","lastPart","lastDuration","playlistMetadataPayload","isLive","renditions","RESOLUTION","resolution","codecs","PlaylistLoader","src","vhs","options","super","logger_","withCredentials","vhs_","addDateRangesToTextTrack_","addDateRangesToTextTrack","vhsOptions","options_","dateRangesStorage_","state","handleMediaupdatetimeout_","handleLoadedPlaylist_","mediaPlaylist","setOffset","setPendingDateRanges","availableDateRanges","getDateRangesToProcess","xhr","playlistRequestError","haveMetadata","playlistString","responseText","startingState","code","metadata","trigger","StreamingHlsPlaylistParserError","playlistObject","playlistInfo","parseManifest_","lastRequest","pendingMedia_","media_","updateMediaUpdateTimeout_","parsedPlaylist","stopRequest","clearTimeout","mediaUpdateTimeout","finalRenditionTimeout","off","oldRequest","onreadystatechange","abort","shouldDelay","delay","setTimeout","mediaChange","mainPlaylistRef","started","load","setupInitialPlaylist","srcUri","clone","isUpdate","pathway","ID","oldPlaylistUri","oldPlaylistId","newPlaylistUri","createCloneURI_","newPlaylistId","createCloneAttributes_","updatedPlaylist","createClonePlaylist_","splice","updateOrDeleteCloneMedia","oldMediaPlaylist","createClonedMediaGroups_","basePlaylist","playlistId","baseID","newUri","newPlaylistID","newMediaPlaylist","newProps","baseURI","hostname","HOST","params","PARAMS","oldAttributes","contentProtection","keyIds","Set","keysystem","keyId","add","toLowerCase","callbackWrapper","response","reqResponse","responseType","responseTime","roundTripTime","requestTime","byteLength","floor","responseHeaders","statusCode","callAllRequestHooks","requestSet","newOptions","requestCallback","callAllResponseHooks","responseSet","responseCallback","xhrFactory","XhrFunction","timeout","beforeRequest","Vhs","_requestCallbackSet","_responseCallbackSet","xhrMethod","beforeRequestOptions","originalAbort","arguments","byterangeStr","byterange","byterangeEnd","byterangeStart","BigInt","segmentXhrHeaders","Range","textRange","formatHexString","e","value","substring","formatAsciiString","String","fromCharCode","createTransferableMessage","transferable","bytes","buffer","byteOffset","initSegmentId","initSegment","segmentKeyId","hexDump","data","Array","prototype","call","step","hex","ascii","j","tagDump","textRanges","utils","freeze","__proto__","SEGMENT_END_FUDGE_PERCENT","playerTimeToProgramTime","playerTime","dateTimeObject","transmuxerPrependedSeconds","videoTimingInfo","transmuxedStart","transmuxedPresentationStart","startOfSegment","offsetFromSegmentStart","originalSegmentVideoDuration","transmuxedPresentationEnd","findSegmentForProgramTime","programTime","nextSegmentStart","lastSegmentStart","lastSegmentDuration","lastSegmentEnd","estimatedStart","indexOf","findSegmentForPlayerTime","segmentEnd","getOffsetFromTimestamp","comparisonTimeStamp","segmentDateTime","segmentTimeEpoch","programTimeEpoch","verifyProgramDateTimeTags","getProgramTime","matchedSegment","seekTime","programTimeObject","mediaSeconds","toISOString","seekToProgramTime","retryCount","seekTo","pauseAfterSeek","tech","hasStarted_","mediaOffset","one","seekToTime","seekedCallback","pause","callbackOnCompleted","cb","readyState","containerRequest","id3Offset","finished","endRequestAndCallback","err","_bytes","progressListener","newPart","overrideMimeType","addEventListener","total","loaded","dashPlaylistUnchanged","sidx","aSegment","bSegment","aByterange","bByterange","dashGroupId","NAME","parseMainXml","mainXml","srcUrl","clientOffset","sidxMapping","previousManifest","manifestUri","removeOldMediaGroupLabels","newMain","updateMain","oldMain","noChanges","minimumUpdatePeriod","timelineStarts","sidxKey","playlistUpdate","equivalentSidx","neitherMap","Boolean","equivalentMap","compareSidxEntry","oldSidxMapping","newSidxMapping","currentSidxInfo","savedSidxInfo","sidxInfo","filterChangedSidxMappings","videoSidx","mediaGroupSidx","DashPlaylistLoader","srcUrlOrPlaylist","mainPlaylistLoader","isPaused_","mainPlaylistLoader_","isMain_","addMetadataToTextTrack","refreshXml_","refreshMedia_","loadedPlaylists_","sidxMapping_","childPlaylist_","mediaRequest_","fin","requestErrored_","subarray","REQUEST_TYPE","container","sidxContainer","internal","playlistExclusionDuration","minimumUpdatePeriodTimeout_","createMupOnMedia_","addSidxSegments_","sidxChanged","isFinalRendition","updateMinimumUpdatePeriodTimeout_","haveMain_","requestMain_","mainChanged","hasPendingRequest","manifestInfo","mainXml_","date","mainLoaded_","parse","handleMain_","syncClientServerClock_","done","utcTiming","clientOffset_","method","serverTime","StreamingDashManifestParserError","locations","addEventStreamToMetadataTrack_","parsedManifest","mpl","mup","createMUPTimeout_","mediaID","mediaChanged","createMediaUpdateTimeout","eventStream","metadataArray","eventStreamNode","cueTime","frames","messageData","defaultKID","replace","Config","GOAL_BUFFER_LENGTH","MAX_GOAL_BUFFER_LENGTH","BACK_BUFFER_LENGTH","GOAL_BUFFER_LENGTH_RATE","INITIAL_BANDWIDTH","BANDWIDTH_VARIANCE","BUFFER_LOW_WATER_LINE","MAX_BUFFER_LOW_WATER_LINE","EXPERIMENTAL_MAX_BUFFER_LOW_WATER_LINE","BUFFER_LOW_WATER_LINE_RATE","BUFFER_HIGH_WATER_LINE","stringToArrayBuffer","string","view","Uint8Array","ArrayBuffer","charCodeAt","browserWorkerPolyFill","workerObj","removeEventListener","createObjectURL","str","Blob","blob","BlobBuilder","append","getBlob","factory","objectUrl","worker","Worker","objURL","terminate","revokeObjectURL","transform","getWorkerString","workerCode$1","commonjsGlobal","globalThis","window","global","self","Stream$8","init","listeners","listener","concat","callbacks","dispose","pipe","destination","flushSource","flush","partialFlush","endTimeline","reset","box","dinf","esds","ftyp","mdat","mfhd","minf","moof","moov","mvex","mvhd","trak","tkhd","mdia","mdhd","hdlr","sdtp","stbl","stsd","traf","trex","trun$1","types","MAJOR_BRAND","MINOR_VERSION","AVC1_BRAND","VIDEO_HDLR","AUDIO_HDLR","HDLR_TYPES","VMHD","SMHD","DREF","STCO","STSC","STSZ","STTS","stream","MAX_UINT32$1","pow","getUint64$5","uint8","dv","DataView","getBigUint64","MAX_SAFE_INTEGER","getUint32","numbers","getUint64","MAX_UINT32","avc1","avcC","btrt","dref","mp4a","pasp","smhd","stco","stsc","stsz","stts","styp","tfdt","tfhd","trun","vmhd","video","audio","payload","setUint32","track","audioobjecttype","samplingfrequencyindex","channelcount","samplerate","sequenceNumber","tracks","trackFragments","boxes","flags","samples","dependsOn","isDependedOn","hasRedundancy","videoSample","audioSample","avc1Box","sps","pps","sequenceParameterSets","pictureParameterSets","width","height","profileIdc","profileCompatibility","levelIdc","sarRatio","hSpacing","vSpacing","samplesize","trackFragmentHeader","trackFragmentDecodeTime","trackFragmentRun","sampleDependencyTable","dataOffset","upperWordBaseMediaDecodeTime","lowerWordBaseMediaDecodeTime","baseMediaDecodeTime","audioTrun","videoTrun","trunHeader","durationPresent","sizePresent","flagsPresent","compositionTimeOffset","bytesOffest","header","sample","isLeading","paddingValue","isNonSyncSample","degradationPriority","silence","secondsToVideoTs","secondsToAudioTs","videoTsToSeconds","audioTsToSeconds","audioTsToVideoTs","videoTsToAudioTs","metadataTsToSeconds","mp4Generator","fileType","movie","groupNalsIntoFrames","nalUnits","currentNal","currentFrame","nalCount","nalUnitType","dts","pts","keyFrame","groupFramesIntoGops","currentGop","gops","extendFirstKeyFrame","shift","createDefaultSample","sampleForFrame","frame","generateSampleTable$1","baseDataOffset","h","concatenateNalData","nalsByteLength","numberOfNals","totalByteLength","generateSampleTableForFrame","concatenateNalDataForFrame","frameUtils$1","generateSampleTable","highPrefix","lowPrefix","zeroFill","makeTable","metaTable","arr","silence_1","coneOfSilence","96000","88200","64000","48000","44100","32000","24000","16000","12000","11025","8000","ONE_SECOND_IN_TS$4","seconds","sampleRate","timestamp","timelineStartPts","keepOriginalTimestamps","clock$2","ONE_SECOND_IN_TS","clock$1","sumFrameByteLengths","array","currentObj","sum","prefixWithSilence","audioAppendStartTs","videoBaseMediaDecodeTime","baseMediaDecodeTimeTs","silentFrame","firstFrame","frameDuration","audioGapDuration","audioFillFrameCount","audioFillDuration","ceil","trimAdtsFramesByEarliestDts","adtsFrames","earliestAllowedDts","minSegmentDts","minSegmentPts","concatenateFrameData","audioFrameUtils$1","ONE_SECOND_IN_TS$3","collectDtsInfo","timelineStartInfo","maxSegmentPts","maxSegmentDts","clearDtsInfo","calculateTrackBaseMediaDecodeTime","scale","trackDecodeInfo$1","USER_DATA_REGISTERED_ITU_T_T35","RBSP_TRAILING_BITS","parseSei","payloadType","payloadSize","userIdentifier","parseUserData","sei","parseCaptionPackets","userData","ccData","discardEmulationPreventionBytes$1","newLength","newData","emulationPreventionBytesPositions","sourceIndex","captionPacketParser","discardEmulationPreventionBytes","Stream$7","cea708Parser","CaptionStream$2","parse708captions_","parse708captions","captionPackets_","ccStreams_","Cea608Stream","cc708Stream_","Cea708Stream","captionServices","cc","event","newCaptionPackets","escapedRBSP","latestDts_","ignoreNextEqualDts_","numSameDts_","flushCCStreams","flushType","flushStream","elem","idx","presortIndex","packet","dispatchCea608Packet","dispatchCea708Packet","activeCea608Channel_","ccStream","setsTextOrXDSActive","setsChannel1Active","setsChannel2Active","CHARACTER_TRANSLATION_708","get708CharFromCode","newCode","within708TextBlock","Cea708Window","windowNum","clearText","pendingNewLine","winAttr","penAttr","penLoc","penColor","visible","rowLock","columnLock","priority","relativePositioning","anchorVertical","anchorHorizontal","anchorPoint","rowCount","virtualRowCount","columnCount","windowStyle","penStyle","getText","rows","rowIdx","newLine","beforeRowOverflow","isEmpty","addText","text","backspace","row","substr","Cea708Service","serviceNum","encoding","currentWindow","windows","createTextDecoder","startPts","win","setCurrentWindow","TextDecoder","level","textDecoder_","serviceProps","captionServiceEncodings","serviceName","test","serviceEncodings","current708Packet","services","new708Packet","add708Bytes","push708Packet","ptsVals","byte0","byte1","packet708","packetData","blockSize","seq","sizeCode","pushServiceBlock","service","initService","handleText","multiByteCharacter","extendedCommands","defineWindow","clearWindows","deleteWindows","displayWindows","hideWindows","toggleWindows","setWindowAttributes","setPenAttributes","setPenColor","setPenLocation","isExtended","getPts","byteIndex","flushDisplayed","char","charCodeArray","isMultiByte","extended","currentByte","nextByte","toHexString","byteArray","byte","decode","unicode","parseInt","firstByte","secondByte","fillOpacity","fillRed","fillGreen","fillBlue","borderType","borderRed","borderGreen","borderBlue","wordWrap","printDirection","scrollDirection","justify","effectSpeed","effectDirection","displayEffect","displayedText","winId","endPts","pushCaption","textTag","penSize","italics","underline","edgeType","fontStyle","fgOpacity","fgRed","fgGreen","fgBlue","bgOpacity","bgRed","bgGreen","bgBlue","edgeRed","edgeGreen","edgeBlue","column","CHARACTER_TRANSLATION","getCharFromCode","BOTTOM_ROW","ROWS","createDisplayBuffer","indent","field","dataChannel","field_","dataChannel_","name_","setConstants","swap","char0","char1","lastControlCode_","PADDING_","RESUME_CAPTION_LOADING_","mode_","END_OF_CAPTION_","clearFormatting","displayed_","nonDisplayed_","startPts_","ROLL_UP_2_ROWS_","rollUpRows_","setRollUp","ROLL_UP_3_ROWS_","ROLL_UP_4_ROWS_","CARRIAGE_RETURN_","shiftRowsUp_","BACKSPACE_","row_","ERASE_DISPLAYED_MEMORY_","ERASE_NON_DISPLAYED_MEMORY_","RESUME_DIRECT_CAPTIONING_","isSpecialCharacter","column_","isExtCharacter","isMidRowCode","addFormatting","isOffsetControlCode","isPAC","formatting_","indentations","isColorPAC","isNormalChar","logWarning","content","trim","line","position","topRow_","BASE_","EXT_","CONTROL_","OFFSET_","newBaseRow","format","reverse","popOn","baseRow","rollUp","paintOn","captionStream","CaptionStream","streamTypes","H264_STREAM_TYPE","ADTS_STREAM_TYPE","METADATA_STREAM_TYPE","Stream$6","MAX_TS","RO_THRESH","TYPE_SHARED","handleRollover$1","reference","direction","abs","TimestampRolloverStream$1","lastDTS","referenceDTS","type_","discontinuity","MetadataStream","timestampRolloverStream","TimestampRolloverStream","handleRollover","typedArrayIndexOf$1","typedArray","element","fromIndex","currentIndex","typedArrayIndexOf","textEncodingDescriptionByte","Iso88591","Utf16","Utf16be","Utf8","percentEncode$1","parseUtf8","decodeURIComponent","parseIso88591$1","unescape","parseSyncSafeInteger$1","frameParsers","mimeTypeEndIndex","descriptionEndIndex","LINK_MIME_TYPE","mimeType","pictureType","description","pictureData","values","owner","privateData","parseId3Frames$1","frameSize","frameHeader","frameStart","tagSize","hasExtendedHeader","parseId3","parseId3Frames","parseSyncSafeInteger","Stream$5","StreamTypes$3","id3","settings","descriptor","bufferSize","dispatchType","chunk","tag","dataAlignmentIndicator","d","timeStamp","TransportPacketStream","TransportParseStream","ElementaryStream","metadataStream","Stream$4","CaptionStream$1","StreamTypes$2","MP2T_PACKET_LENGTH$1","SYNC_BYTE$1","bytesInBuffer","everything","parsePsi","parsePat","parsePmt","packetsWaitingForPmt","programMapTable","psi","payloadUnitStartIndicator","pat","section_number","last_section_number","pmtPid","pmt","sectionLength","tableEnd","programInfoLength","streamType","pid","processPes_","STREAM_TYPES","h264","adts","segmentHadPmt","timedMetadata","parsePes","pes","ptsDtsFlags","startPrefix","packetLength","forceFlush","fragment","packetFlushable","trackId","codec","flushStreams_","m2ts$1","PAT_PID","MP2T_PACKET_LENGTH","AdtsStream$1","m2ts_1","Stream$3","ONE_SECOND_IN_TS$2","ADTS_SAMPLING_FREQUENCIES$1","handlePartialSegments","frameNum","skipWarn_","frameLength","protectionSkipBytes","oldBuffer","sampleCount","adtsFrameDuration","ExpGolomb$1","workingData","workingBytesAvailable","workingWord","workingBitsAvailable","bitsAvailable","loadWord","workingBytes","availableBytes","skipBits","skipBytes","readBits","bits","valu","skipLeadingZeros","leadingZeroCount","skipUnsignedExpGolomb","skipExpGolomb","readUnsignedExpGolomb","clz","readExpGolomb","readBoolean","readUnsignedByte","H264Stream$1","NalByteStream","PROFILES_WITH_OPTIONAL_SPS_DATA","expGolomb","Stream$2","ExpGolomb","syncPoint","swapBuffer","len","100","110","122","244","44","83","86","118","128","138","139","134","currentPts","currentDts","readSequenceParameterSet","skipScalingList","nalByteStream","nalUnitTypeCode","config","expGolombDecoder","deltaScale","lastScale","nextScale","chromaFormatIdc","picOrderCntType","numRefFramesInPicOrderCntCycle","picWidthInMbsMinus1","picHeightInMapUnitsMinus1","frameMbsOnlyFlag","scalingListCount","aspectRatioIdc","frameCropLeftOffset","frameCropRightOffset","frameCropTopOffset","frameCropBottomOffset","AacStream$1","H264Stream","ADTS_SAMPLING_FREQUENCIES","parseId3TagSize","returnSize","footerPresent","getId3Offset","isLikelyAacData$1","percentEncode","parseIso88591","parseAdtsSize","lowThree","middle","highTwo","parseType$5","parseSampleRate","parseAacTimestamp","isLikelyAacData","parseType","Stream$1","aacUtils","setTimestamp","bytesLeft","tempLength","VideoSegmentStream","AudioSegmentStream","Transmuxer","CoalesceStream","aac","AUDIO_PROPERTIES$1","audioProperties","VIDEO_PROPERTIES$1","videoProperties","Stream","mp4","frameUtils","audioFrameUtils","trackDecodeInfo","m2ts","clock","AdtsStream","AacStream","ONE_SECOND_IN_TS$1","AUDIO_PROPERTIES","VIDEO_PROPERTIES","retriggerForStream","addPipelineLogRetriggers","transmuxer","pipeline","arrayEquals","generateSegmentTimingInfo","startDts","endDts","prependedContentDuration","ptsOffsetFromDts","decodeDuration","presentationDuration","firstSequenceNumber","prop","setEarliestDts","earliestDts","setVideoBaseMediaDecodeTime","setAudioAppendStart","videoClockCyclesOfSilencePrefixed","gopsToAlignWith","minPTS","gopCache_","nalUnit","gopForFusion","firstGop","lastGop","resetStream_","getGopForFusion_","alignedGops","alignGopsAtEnd","alignGopsAtEnd_","alignGopsAtStart_","gop","pop","dtsDistance","nearestGopObj","currentGopObj","halfSecond","allowableOverlap","nearestDistance","alignIndex","gopIndex","align","alignEndIndex","matchFound","trimIndex","alignGopsWith","newGopsToAlignWith","numberOfTracks","remux","remuxTracks","pendingTracks","videoTrack","pendingBoxes","pendingCaptions","pendingMetadata","pendingBytes","emittedTracks","output","audioTrack","caption","captions","captionStreams","info","setRemux","val","hasFlushed","transmuxPipeline_","setupAacPipeline","aacStream","audioTimestampRolloverStream","timedMetadataTimestampRolloverStream","adtsStream","coalesceStream","headOfPipeline","audioSegmentStream","getLogTrigger_","hasAudio","hasVideo","setupTsPipeline","packetStream","parseStream","elementaryStream","h264Stream","videoSegmentStream","id3Frame","setBaseMediaDecodeTime","isAac","resetCaptions","inspectMp4","textifyMp4","toUnsigned$3","toHexString$1","bin","toUnsigned","parseType$4","parseType_1","toUnsigned$2","parseType$3","findBox$5","path","subresults","findBox_1","toUnsigned$1","getUint64$4","version","parseTfdt$3","baseDataOffsetPresent","sampleDescriptionIndexPresent","defaultSampleDurationPresent","defaultSampleSizePresent","defaultSampleFlagsPresent","durationIsEmpty","defaultBaseIsMoof","sampleDescriptionIndex","defaultSampleDuration","defaultSampleSize","defaultSampleFlags","baseDataOffsetIsMoof","parseTfhd$2","getUint64$3","parseSidx","references","referenceId","timescale","earliestPresentationTime","firstOffset","referenceCount","getUint16","referenceType","referencedSize","subsegmentDuration","startsWithSap","sapType","sapDeltaTime","parseSidx_1","parseSampleFlags$1","parseSampleFlags_1","parseSampleFlags","dataOffsetPresent","firstSampleFlagsPresent","sampleDurationPresent","sampleSizePresent","sampleFlagsPresent","sampleCompositionTimeOffsetPresent","getInt32","parseTrun$2","numberHelpers","getUint64$2","parseMp4Date","parseType$2","findBox$4","nalParse","avcStream","avcView","dataReferenceIndex","horizresolution","vertresolution","frameCount","depth","numOfPictureParameterSets","nalSize","configurationVersion","avcProfileIndication","avcLevelIndication","lengthSizeMinusOne","numOfSequenceParameterSets","bufferSizeDB","maxBitrate","avgBitrate","edts","elst","getUint8","edits","entryCount","mediaTime","mediaRate","esId","streamPriority","decoderConfig","objectProfileIndication","decoderConfigDescriptor","audioObjectType","samplingFrequencyIndex","channelConfiguration","majorBrand","minorVersion","compatibleBrands","dataReferences","handlerType","escape","nals","language","creationTime","modificationTime","streamDescriptor","rate","volume","matrix","Uint32Array","nextTrackId","pdin","initialDelay","balance","ctts","compositionOffsets","sampleOffset","stss","syncSamples","chunkOffsets","sampleToChunks","firstChunk","samplesPerChunk","sampleDescriptions","sampleSize","entries","timeToSamples","sampleDelta","layer","alternateGroup","defaultSampleDescriptionIndex","sampleDependsOn","sampleIsDependedOn","sampleHasRedundancy","samplePaddingValue","sampleIsDifferenceSample","sampleDegradationPriority","graphicsmode","opcolor","Uint16Array","ab","v","z","inspectedMp4","prefix","match","JSON","stringify","mp4Inspector","inspect","textify","findBox","parseTraf","parseTfdt","parseHdlr","parseTfhd","parseTrun","uint8ToCString$1","curChar","retString","uint8ToCString","getUint64$1","parseEmsgBox","boxData","scheme_id_uri","presentation_time","presentation_time_delta","event_duration","message_data","emsgBox","isValidEmsgBox","scaleTime","presentationTime","timeDelta","emsg","hasScheme","isValidV0Box","isDefined","isValidV1Box","emsg$1","compositionStartTime","getVideoTrackIds","getTracks","getTimescaleFromMediaHeader$1","getEmsgID3","window_1","findBox$3","parseType$1","parseTfhd$1","parseTrun$1","parseTfdt$2","window$2","traks","trafs","lowestTime","baseTime","isNaN","isFinite","timescales","trafBoxes","parsedTfhd","parsedTfdt","parsedTrun","videoTrackIds","hdlrs","tkhds","tkhdVersion","codecConfig","codecConfigType","codecBox","segmentData","emsgBoxes","parsedBox","parsedId3Frames","probe$2","getTimescaleFromMediaHeader","findBox$2","window$1","getMdatTrafPairs$2","mdats","mdatTrafPairs","matchingTraf","parseSamples$2","truns","allSamples","trackRun","getMdatTrafPairs","parseSamples","findBox$1","parseTfdt$1","getMdatTrafPairs$1","parseSamples$1","mapToSample","approximateOffset","findSeiNals","seiNal","lastMatchedSample","logs","seiNals","matchingSample","parseCaptionNals","videoTrackId","captionNals","pair","headerInfo","parseEmbeddedCaptions","trackNals","CaptionParser","segmentCache","parsedCaptions","parsingPartial","isInitialized","isPartial","isNewInit","parsedData","cachedSegment","pushNals","nal","clearParsedCaptions","resetCaptionStream","clearAllCaptions","captionParser","WebVttParser","parseSegment","vttCues","mdatBox","trafBox","tfdtBox","tfhdBox","trunBoxes","mdatOffset","UTF_8","textDecoder","sampleData","vtteBox","vttcBoxes","vttcBox","paylBox","sttgBox","cueText","console","webvttParser","StreamTypes$1","parsePid","parsePayloadUnitStartIndicator","parseAdaptionField","pusi","payloadOffset","parsePesType","parsePesTime","parseNalUnitType","videoPacketContainsKeyFrame","nalType","frameBuffer","frameI","frameSyncPoint","foundKeyFrame","probe$1","StreamTypes","probe","ts","SYNC_BYTE","parsePsi_","table","parseAudioPes_","pesType","parsed","endLoop","parseVideoPes_","firstKeyFrame","adjustTimestamp_","segmentInfo","baseTimestamp","audioBaseTimestamp","dtsTime","ptsTime","videoBaseTimestamp","inspectAac_","audioCount","audioTimescale","inspectTs_","isAacData","tsInspector","wireTransmuxerEvents","initArray","postMessage","action","gopInfo","timingInfo","videoSegmentTimingInfo","presentation","audioSegmentTimingInfo","trackInfo","audioTimingInfo","MessageHandlers","trackIds","webVttParser","mp4VttCues","id3Frames","emsgData","baseStartTime","tsStartTime","timeInfo","videoStart","audioStart","timestampOffset","round","appendStart","onmessage","messageHandlers","TransmuxWorker","handleData_","transmuxedData","videoFrameDtsTime","videoFramePtsTime","handleDone_","handleGopInfo_","processTransmux","audioAppendStart","onData","onTrackInfo","onAudioTimingInfo","onVideoTimingInfo","onVideoSegmentTimingInfo","onAudioSegmentTimingInfo","onId3","onCaptions","onDone","onEndedTimeline","onTransmuxerLog","isEndOfTimeline","triggerSegmentEventFn","waitForEndedTimelineEvent","handleMessage","currentTransmux","dequeue","handleError","StreamingFailedToTransmuxSegment","segmentInfoPayload","onerror","isArray","transmuxQueue","processAction","enqueueAction","transmux","createTransmuxer","term","segmentTransmuxer","workerCallback","endAction","listenForEndEvent","isArrayBuffer","transfers","REQUEST_ERRORS","FAILURE","TIMEOUT","ABORTED","WEB_VTT_CODEC","abortAll","activeXhrs","getRequestStats","getProgressStats","progressEvent","target","stats","handleErrors","handleKeyResponse","objects","finishProcessingFn","errorObj","keyInfo","initMp4Text","parseMp4TextSegment","doneFn","parseInitSegment","handleInitSegmentResponse","encryptedBytes","parseError","handleSegmentResponse","newBytes","lastReachedChar","transmuxAndNotify","trackInfoFn","timingInfoFn","videoSegmentTimingInfoFn","audioSegmentTimingInfoFn","id3Fn","captionsFn","endedTimelineFn","dataFn","fmp4Tracks","isMuxed","audioStartFn","audioEndFn","videoStartFn","videoEndFn","finish","probeResult","handleSegmentBytes","bytesAsUint8Array","isFmp4","isMp4TextSegment","audioCodec","videoCodec","finishLoading","decrypt","decryptionWorker","decryptionHandler","decrypted","keyBytes","decryptError","StreamingFailedToDecryptSegment","encrypted","iv","decryptSegment","requestId","decryptedBytes","waitForCompletion","didError","segmentFinish","endOfAllRequests","handleLoadEnd","loadendState","abortFn","calledAbortFn","handleProgress","progressFn","firstBytesReceivedAt","mediaSegmentRequest","xhrOptions","keyRequestOptions","keyRequestCallback","keyXhr","differentMapKey","mapKeyRequestOptions","mapKeyRequestCallback","mapKeyXhr","initSegmentOptions","initSegmentRequestCallback","initSegmentXhr","segmentRequestOptions","segmentRequestCallback","segmentXhr","activeXhr","logFn$1","getCodecs","mediaAttributes","isMaat","audioGroup","unwrapCodecList","codecList","details","codecCount","codecObj","codecsForPlaylist","codecInfo","defaultCodecs","logFn","representationToString","representation","safeGetComputedStyle","el","property","getComputedStyle","stableSort","sortFn","newArray","left","right","cmp","comparePlaylistBandwidth","leftBandwidth","rightBandwidth","comparePlaylistResolution","leftWidth","rightWidth","simpleSelector","playerBandwidth","playerWidth","playerHeight","limitRenditionByPlayerDimensions","playlistController","getAudioTrackPlaylists_","audioOnly","sortedPlaylistReps","rep","enabledPlaylistReps","bandwidthPlaylistReps","highestRemainingBandwidthRep","bandwidthBestRep","chosenRep","haveResolution","resolutionBestRepList","resolutionBestRep","resolutionPlusOneList","resolutionPlusOneSmallest","resolutionPlusOneRep","leastPixelDiffRep","leastPixelDiffSelector","leastPixelDiffList","pixelDiff","lastBandwidthSelector","pixelRatio","useDevicePixelRatio","devicePixelRatio","customPixelRatio","systemBandwidth","tech_","playlistController_","movingAverageBandwidthSelector","decay","average","lastSystemBandwidth","minRebufferMaxBandwidthSelector","currentTimeline","syncController","compatiblePlaylists","enabledPlaylists","bandwidthPlaylists","rebufferingEstimates","getSyncPoint","numRequests","requestTimeEstimate","rebufferingImpact","noRebufferingPlaylists","estimate","lowestBitrateCompatibleVariantSelector","playlistsWithVideo","concatSegments","segmentObj","tempBuffer","compactSegmentUrlDescription","pathname","createCaptionsTrackIfNotExists","inbandTextTracks","instreamId","textTracks","getTrackById","def","captionService","default","addRemoteTextTrack","kind","addCaptionData","captionArray","Cue","WebKitDataCue","VTTCue","cue","positionAlign","addCue","deprecateOldCue","defineProperties","addMetadata","videoDuration","metadataTrack","metadataTrack_","cues","cuesArray","cuesGroupedByStartTime","timeSlot","sortedStartTimes","cueGroup","finiteDuration","nextTime","dateRangeAttr","scte35Out","scte35In","dateRangeKeysToOmit","addDateRangeMetadata","createMetadataTrackIfNotExists","browser","IS_ANY_SAFARI","inBandMetadataTrackDispatchType","removeCuesFromTrack","removeCue","removeDuplicateCuesFromTrack","uniqueCues","cueKey","gopsSafeToAlignWith","mapping","currentTimePts","updateGopBuffer","removeGopBuffer","updatedBuffer","shallowEqual","akeys","bkeys","getSyncSegmentCandidate","targetTime","timelineSegments","timeline","MIN_BACK_BUFFER","CHECK_BUFFER_DELAY","finite","num","MIN_SEGMENT_DURATION_TO_SAVE_STATS","illegalMediaSwitch","loaderType","startingMedia","safeBackBufferTrimTime","trimTime","maxTrimTime","segmentInfoString","mediaIndex","segmentLen","selection","isSyncRequest","independent","hasPartIndex","zeroBasedPartCount","timingInfoPropertyForMedia","timestampOffsetForSegment","segmentTimeline","overrideCheck","shouldWaitForTimelineChange","timelineChangeController","audioDisabled","lastMainTimelineChange","lastTimelineChange","to","pendingAudioTimelineChange","pendingTimelineChange","shouldFixBadTimelineChanges","pendingMainTimelineChange","hasPendingTimelineChanges","differentPendingChanges","isNotInitialPendingTimelineChange","from","isAudioTimelineBehind","segmentLoader","timelineChangeController_","checkAndFixTimelines","pendingSegment_","waitingForTimelineChange","currentTimeline_","loaderType_","audioDisabled_","mediaDuration","timingInfos","maxDuration","typeTimingInfo","segmentTooLong","getTroublesomeSegmentDurationMessage","sourceType","isSegmentWayTooLong","isSegmentSlightlyTooLong","segmentTooLongMessage","severity","isEncrypted","ke","isMediaInitialization","SegmentLoader","TypeError","mediaSource","throughput","roundTrip","resetStats_","hasPlayed_","hasPlayed","currentTime_","seekable_","seeking_","seeking","duration_","mediaSource_","currentMediaInfo_","startingMediaInfo_","segmentMetadataTrack_","segmentMetadataTrack","goalBufferLength_","goalBufferLength","sourceType_","sourceUpdater_","sourceUpdater","inbandTextTracks_","state_","shouldSaveSegmentTimingInfo_","useDtsForTimestampOffset_","useDtsForTimestampOffset","captionServices_","checkBufferTimeout_","error_","shouldForceTimestampOffsetAfterResync_","xhrOptions_","pendingSegments_","isPendingTimestampOffset_","gopBuffer_","timeMapping_","safeAppend_","appendInitSegment_","playlistOfLastInitSegment_","callQueue_","loadQueue_","metadataQueue_","waitingOnRemove_","quotaExceededErrorRetryTimeout_","activeInitSegmentId_","initSegments_","cacheEncryptionKeys_","cacheEncryptionKeys","keyCache_","decrypter_","decrypter","syncController_","syncPoint_","transmuxer_","createTransmuxer_","triggerSyncInfoUpdate_","isEndOfStream_","ended_","fetchAtBuffer_","defineProperty","newState","hasEnoughInfoToAppend_","processCallQueue_","hasEnoughInfoToLoad_","processLoadQueue_","getMediaSequenceSync","mediaBytesTransferred","mediaRequests","mediaRequestsAborted","mediaRequestsTimedout","mediaRequestsErrored","mediaTransferDuration","mediaSecondsLoaded","mediaAppends","abort_","enable","removeAudio","clearPendingTimelineChange","paused","monitorBuffer_","abortRequests","getMediaInfo_","videoBuffered","audioBuffered","storedMap","storedKey","playlist_","couldBeginLoading_","init_","resetEverything","newPlaylist","oldPlaylist","syncInfo","setDateTimeMappingForStart","oldId","mediaSequenceSync_","buffered_","diagnostics","isLLHLS","resetLoader","resyncLoader","mediaSequenceDiff","saveExpiredSegmentInfo","remove","resetAppendedStatus","isHlsTs","force","removesRemaining","removeFinished","removeVideo","monitorBufferTick_","fillBuffer_","updating","chooseNextRequest_","loadSegment_","appendedLastSegment","appendedLastPart","bufferedTime","preloaded","haveEnoughBuffer","next","isReliable","getSyncInfoFromMediaSequenceSync_","StreamingFailedToSelectNextSegment","mediaInfoForTime","nextSegment","hasIndependentSegments","independentSegments","lastSegmentLastPart","ended","forceTimestampOffset","generateSegmentInfo_","finalTargetTime","mediaSequenceSyncInfo","getSyncInfoForTime","isAppended","nextMediaSequenceSyncInfo","random","timestampOffsetForSegment_","audioBufferedEnd","audioTimestampOffset","videoTimestampOffset","measuredBandwidth","requestTimeRemaining","timeUntilRebuffer$1","switchCandidate","timeSavedBySwitching","minimumTimeSaving","simpleSegment","earlyAbortWhenNeeded_","checkForAbort_","checkForIllegalMediaSwitch","timeType","timingInfoProperty","captionData","hasAppendedData_","handleCaptions_","captionTracks","captionTrack","trackName","handleId3_","callQueue","fun","loadQueue","getCurrentMediaInfo_","ready","setTimeMapping_","updateMediaSecondsLoaded_","initSegmentForMap","segmentKey","useVideoTimingInfo","firstVideoFrameTimeForData","trueSegmentStart_","currentStart","currentVideoTimestampOffset","updateAppendInitSegmentStatus","updateSourceBufferTimestampOffset_","updateTimingInfoEnd_","saveSegmentTimingInfo","shouldSaveTimelineMapping","processMetadataQueue_","appendData_","changedTimestampOffset","audioBufferStart","audioBufferEnd","videoBufferStart","videoBufferEnd","appendToSourceBuffer_","timeToRemoveUntil","StreamingFailedToAppendSegment","handleQuotaExceededError_","appendBuffer","handleAppendError_","segmentTimingInfo","transmuxedDecodeStart","transmuxedDecodeEnd","getInitSegmentAndUpdateState_","trimBackBuffer_","updateTransmuxerAndRequestSegment_","shouldUpdateTransmuxerTimestampOffset_","createSimplifiedSegmentObj_","isEndOfStream","isWalkingForward","isDiscontinuity","handleAbort_","handleProgress_","handleTrackInfo_","handleTimingInfo_","handleSegmentTimingInfo_","segmentRequestFinished_","segInfo","removeToTime","previousSegment","bandwidthInfo","saveTransferStats_","handleTimeout_","saveBandwidthRelatedStats_","waitForAppendsToComplete_","timelineMapping","mappingForTimeline","waitForVideo","waitForAudio","waitingOnAppends","checkAppendsDone_","videoQueueCallback","audioQueueCallback","handleAppendsDone_","illegalMediaSwitchError","didChange","getSegmentStartTimeForTimestampOffsetCalculation_","prioritizedTimingInfo","markAppended","segmentDurationMessage","recordThroughput_","addSegmentMetadataCue_","badSegmentGuess","badPartGuess","endOfStream","segmentProcessingTime","segmentProcessingThroughput","custom","dateTimeString","noop","toTitleCase","w","toUpperCase","bufferTypes","sourceBuffer","queuePending","nextQueueIndexOfType","queue","queueEntry","shiftQueue","queueIndex","cleanupBuffer","titleType","inSourceBuffers","sourceBuffers","actions","onError","addSourceBuffer","mime","removeSourceBuffer","changeType","newCodecBase","oldCodec","oldCodecBase","codecsChangeInfo","StreamingCodecsChangeError","pushQueue","onUpdateend","bufferedRangesForType","descriptiveString","SourceUpdater","sourceopenListener_","audioTimestampOffset_","videoTimestampOffset_","delayedAudioAppendQueue_","videoAppendQueued_","onVideoUpdateEnd_","onAudioUpdateEnd_","onVideoError_","videoError_","onAudioError_","audioError_","createdSourceBuffers_","initializedEme_","triggeredReady_","triggerReady","hasCreatedSourceBuffers","hasInitializedAnyEme","addOrChangeSourceBuffers","canRemoveSourceBuffer","IS_FIREFOX","MediaSource","SourceBuffer","constructor","canChangeType","processedAppend_","videoBuffer","que","audioBuffer","uint8ToUtf8","uintArray","bufferToHexString","uInt8Buffer","padStart","VTT_LINE_TERMINATORS","NoVttJsError","VTTSegmentLoader","subtitlesTrack_","featuresNativeTextTracks_","featuresNativeTextTracks","loadVttJs","combinedByteLength","combinedSegment","timestampOffsetForTimeline","checkTimestampOffset","skipEmptySegments_","empty","stopForError","isMp4WebVttSegmentWithCues","WebVTT","then","requested","parseVTTCues_","StreamingVttParserError","updateTimeMapping_","timelines","isVttType","isTextResult","isFmp4VttSegment","vttCue","cueSetting","keyValString","decoder","decodeBytesToString","timestampmap","MPEGTS","LOCAL","parseMp4VttCues_","StringDecoder","Parser","vttjs","oncue","ontimestampmap","onparsingerror","mapData","mappingObj","mpegTsInSeconds","diff","handleRollover_","firstStart","lastStart","valueIn90khz","referenceIn90khz","findAdCue","adStartTime","adEndTime","updateAdCues","cueOut","parseFloat","adOffset","adTotal","cueOutCont","SyncInfo","appended","start_","end_","segmentIndex_","partIndex_","appended_","SyncInfoData","segmentSyncInfo","partsSyncInfo","segmentSyncInfo_","partsSyncInfo_","partSyncInfo","MediaSequenceSync","storage_","diagnostics_","isReliable_","syncInfoData","resetAppendStatus","isReliablePlaylist_","updateStorage_","calculateBaseTime_","isInRange","get","startingMediaSequence","startingTime","newStorage","newDiagnostics","currentMediaSequence","prevSyncInfoData","segmentStart","segmentIsAppended","currentPartStart","partStart","partEnd","partIsAppended","fallback","minMediaSequenceFromStorage","DependantMediaSequenceSync","parent","parent_","getSyncInfoForMediaSequence","MAX_MEDIA_SEQUENCE_DIFF_FOR_SYNC","syncPointStrategies","run","mediaSequenceSync","timelineToDatetimeMappings","lastDistance","datetimeMapping","segmentTime","distance","discontinuityStarts","discontinuitySequence","discontinuitySync","discontinuities","SyncController","vtt","mediaSequenceStorage_","vodSyncPointStrategy","find","syncPoints","runStrategies_","syncPointInfo","strategy","selectedSegment","selectSyncPoint_","bestSyncPoint","bestDistance","bestStrategy","newDistance","lastRemovedSegment","playlistTimestamp","didCalculateSegmentTimeMapping","calculateSegmentTimeMapping_","saveDiscontinuitySyncInfo_","dateTime","accuracy","mediaIndexDiff","TimelineChangeController","pendingTimelineChanges_","lastTimelineChanges_","timelineChangeInfo","workerCode","_proto","_length","_i","unpad","padded","precompute","tables","encTable","decTable","sbox","sboxInv","x","xInv","th","x2","x4","x8","tEnc","tDec","aesTables","AES","tmp","_tables","keyLen","rcon","encKey","decKey","_key","encrypted0","encrypted1","encrypted2","encrypted3","out","a2","b2","c2","nInnerRounds","kIndex","table0","table1","table2","table3","AsyncStream","jobs","timeout_","processJob_","job","ntoh","word","initVector","encrypted32","Int32Array","decipher","decrypted32","init0","init1","init2","init3","wordIx","Decrypter","STEP","asyncStream_","decryptChunk_","isArrayBufferView","isView","audioTrackKind_","characteristics","stopLoaders","activePlaylistLoader","startLoaders","playlistLoader","onGroupChanged","segmentLoaders","mainSegmentLoader","mediaTypes","activeTrack","activeGroup","getActiveGroup","previousActiveLoader","lastGroup","lastGroup_","lastTrack_","isMainPlaylist","onGroupChanging","onTrackChanged","lastTrack","pc","selectPlaylist","fastQualityChange_","setAudio","excludePlaylist","defaultTrack","enabled","SUBTITLES","mode","setupListeners","requestOptions","initialize","groups","variantLabel","AudioTrack","useForcedSubtitles","forced","autoselect","groupMatch","list","variants","groupKeys","groupPropertyList","props","activeTrack_","setupMediaGroups","audioSegmentLoader","activeAudioGroup","onAudioTrackChanged","audioTracks","remoteTextTracks","clearTracks","addTrack","createMediaTypes","SteeringManifest","priority_","pathwayClones_","number","version_","ttl_","reloadUri_","ContentSteeringController","currentPathway","defaultPathway","queryBeforeStart","availablePathways_","steeringManifest","proxyServerUrl_","manifestType_","ttlTimeout_","request_","currentPathwayClones","nextPathwayClones","excludedSteeringManifestURLs","xhr_","getBandwidth_","baseUrl","steeringTag","serverUri","steeringUri","serverURL","startsWith","decodeDataUriManifest_","reloadUri","pathwayId","defaultServiceLocation","proxyServerURL","initial","getRequestURI","contentSteeringInfo","errorInfo","retrySeconds","startTTLTimeout_","steeringManifestJson","StreamingContentSteeringParserError","assignSteeringProperties_","parsedMetadata","contentSteeringManifest","steeringUrl","steeringUrlObject","proxyServerUrlObject","encodeURI","setSteeringParams_","dataUri","atob","urlObject","getPathway","networkThroughput","pathwayKey","throughputKey","steeringJson","VERSION","ttl","TTL","pathwayClones","chooseNextPathway","pathwaysByPriority","nextPathway","proxyURI","setProxyServerUrl_","steeringURI","ttlMS","requestSteeringManifest","clearTTLTimeout_","clear","baseURL","newTag","debounce","wait","timeoutId","ABORT_EARLY_EXCLUSION_SECONDS","Vhs$1","loaderStats","sumLoaderStat","stat","audioSegmentLoader_","mainSegmentLoader_","shouldSwitchToMedia","currentPlaylist","nextPlaylist","bufferLowWaterLine","bufferHighWaterLine","bufferBasedABR","sharedLogLine","isBuffered","forwardBuffer","maxBufferLowWaterLine","nextBandwidth","currBandwidth","logLine","PlaylistController","externVhs","useCueTags","enableLowInitialPlaylist","experimentalUseMMS","maxPlaylistRetries","player_","useCueTags_","usingManagedMediaSource_","cueTagsTrack_","addTextTrack","requestOptions_","pauseLoading","mediaTypes_","ManagedMediaSource","el_","disableRemotePlayback","handleDurationChange_","handleSourceOpen_","handleSourceEnded_","keyStatusMap_","segmentLoaderSettings","setupMainPlaylistLoaderListeners_","subtitleSegmentLoader_","Promise","resolve","reject","onLoad","addWebVttScript_","getBandwidth","contentSteeringController_","setupSegmentLoaderListeners_","startABRTimer_","stopABRTimer_","triggeredFmp4Usage","loadOnPlay_","timeToLoadedData__","mainAppendsToLoadedData__","audioAppendsToLoadedData__","timeToLoadedDataStart","mainAppendsToLoadedData_","audioAppendsToLoadedData_","reason","shouldSwitchToMedia_","switchMedia_","cause","newId","renditionInfo","mediaPlaylists","dashMediaPlaylists","serviceLocation","abrTimer_","setInterval","checkABR_","scrubbing","clearInterval","defaultPlaylists","defaultGroup","requestTimeout","triggerPresenceUsage_","setupFirstPlay","selectedMedia","attachContentSteeringListeners_","initContentSteeringController_","excludeUnsupportedVariants_","selectInitialPlaylist","initialMedia_","haveJsonSource","handleUpdatedMediaPlaylist","playlistToExclude","isPaused","waitingForFastQualityPlaylistReceived_","runFastQualitySwitch_","bubbles","lastExcludeReason_","playlistOutdated","stuckAtPlaylistEnd_","playlistLoaderEvents","eventName","updateAdCues_","updateDuration","defaultDemuxed","audioGroupKeys","mediaGroup","onSyncInfoUpdate_","onEndOfStream","newTime","setCurrentTime","delegateLoaders_","updateCodecs","tryToCreateSourceBuffers_","getCodecsOrExclude_","segmentLoaderEvents","startPoint","timeOffset","autoplay","playPromise","play","mainMediaInfo","getExpiredTime","absolutePlaylistEnd","contentSteering","pathwayAttribute_","reIncludeDelay","excludePathway","excludeThenChangePathway_","addAvailablePathway","reincluded","errorMessage","delayDuration","fnNames","loaders","dontFilterPlaylist","loader","fnName","calculatedEnd","mainSeekable","audioSeekable","mainStart","mainEnd","audioEnd","getSeekableRange_","oldSeekable","computeFinalSeekable_","seekableRanges","updateDuration_","setDuration","usingAudioLoader","hasMainMediaInfo","hasAudioMediaInfo","getPendingSegmentPlaylist","playlistCodecs","supportFunction","unsupportedCodecs","unsupportedAudio","supporter","variantAudioGroup","switchMessages","newCodec","areMediaTypesKnown_","createSourceBuffers","codecString","excludeIncompatibleVariants_","ids","unsupported","codecCount_","videoDetails","audioDetails","exclusionReasons","variantCodecs","variantCodecCount","variantVideoDetails","variantAudioDetails","newMax","assignTagProperties","clearAvailablePathways","contentSteeringEvents","didDashTagChange","didDASHTagChange","didPathwaysChange","availablePathways","getAvailablePathways","newPathways","resetContentSteeringController_","handlePathwayClones_","didEnablePlaylists","differentPathwayId","steeringExclusion","noExcludeUntil","shouldExclude","changeSegmentPathway_","hasClones","newClone","updateOrDeleteClone","oldClone","equalPathwayClones_","playlistsToClone","addClonePathway","aParams","bParams","switchMediaForDASHContentSteering_","nonUsableKeyStatusCount","NON_USABLE","keyIdSet","getKeyIdSet","USABLE","hasUsableKeyStatus","nonUsableExclusion","isNonHD","excludedForNonUsableKey","isString","keyIdHexString","formattedKeyIdString","addKeyStatus_","excludeNonUsableThenChangePlaylist_","excludeNonUsablePlaylistsByKeyId_","enableFunction","playlistID","changePlaylistFn","incompatible","currentlyEnabled","Representation","vhsHandler","qualityChangeFunction","frameRate","renditionSelectionMixin","representations","timerCancelEvents","PlaybackWatcher","allowSeeksWithinUnsafeLiveWindow","liveRangeSafeTimeDelta","playedRanges_","consecutiveUpdates","lastRecordedTime","checkCurrentTimeTimeout_","playHandler","monitorCurrentTime_","canPlayHandler","waitingHandler","techWaiting_","cancelTimerHandler","resetTimeUpdate_","loaderTypes","loaderChecks","resetSegmentDownloads_","updateend","checkSegmentDownloads_","setSeekingHandlers","seekingAppendCheck_","fixesBadSeeks_","clearSeekingAppendCheck_","watchForBadSeeking_","checkCurrentTime_","isBufferedDifferent","bufferedRanges","waiting_","playedRanges","isAfterSeekableRange","afterSeekableWindow_","beforeSeekableWindow_","minAppendedDuration","bufferedToCheck","timeAhead","nextRange","currentRange","livePoint","videoUnderflow","videoUnderflow_","skipTheGap_","allowedEnd","gap","lastVideoRange","videoRange","audioRange","gapFromVideoUnderflow_","scheduledCurrentTime","gapInfo","gaps","defaultOptions","errorInterval","IWillNotUseThisInPlugins","sourceObj","currentSource_","currentSource","initPlugin","player","lastCalled","localOptions","loadedMetadataHandler","setSource","errorHandler","getSource","cleanupEvents","reinitPlugin","reloadSourceOnError","version$4","version$3","version$2","version$1","STANDARD_PLAYLIST_SELECTOR","INITIAL_PLAYLIST_SELECTOR","LOCAL_STORAGE_KEY","handleVhsMediaChange","qualityLevels","selectedIndex","selectedIndex_","handleVhsLoadedMetadata","addQualityLevel","canPlaySource","emeKeySystems","keySystemOptions","mainPlaylist","audioPlaylist","videoContentType","audioContentType","keySystemContentTypes","keySystem","pssh","getAllPsshKeySystemsOptions","keySystems","keySystemsArr","keySystemsOptions","keySystemsObj","waitForKeySessionCreation","sourceKeySystems","audioMedia","mainPlaylists","eme","initializeMediaKeys","keySystemsOptionsArr","initializationFinishedPromises","keySessionCreatedPromises","race","all","setupEmeOptions","sourceOptions","getVhsLocalStorage","localStorage","storedObject","getItem","updateVhsLocalStorage","objectToStore","setItem","expandDataUri","addOnRequestHook","addOnResponseHook","removeOnRequestHook","removeOnResponseHook","supportsNativeHls","createElement","getTech","isSupported","canPlay","some","canItPlay","canPlayType","supportsNativeDash","supportsTypeNatively","onRequest","onResponse","offRequest","offResponse","Component","getComponent","VhsHandler","initialBandwidth","playerId","_player","getPlayer","source_","ignoreNextSeekingEvent_","setOptions_","overrideNative","overrideNativeAudioTracks","overrideNativeVideoTracks","featuresNativeVideoTracks","featuresNativeAudioTracks","fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement","contains","useBandwidthFromLocalStorage","useNetworkInformationApi","option","playbackWatcherOptions","playbackWatcher_","attachStreamingEventListeners_","players","defaultSelector","playerBandwidthEst","networkInformation","navigator","connection","mozConnection","webkitConnection","tenMbpsAsBitsPerSecond","networkInfoBandwidthEstBitsPerSec","downlink","invBandwidth","invThroughput","systemBitrate","enumerable","mediaRequests_","mediaRequestsAborted_","mediaRequestsTimedout_","mediaRequestsErrored_","mediaTransferDuration_","mediaBytesTransferred_","mediaSecondsLoaded_","mediaAppends_","mainAppendsToLoadedData","audioAppendsToLoadedData","appendsToLoadedData","appendsToLoadedData_","timeToLoadedData","timeToLoadedData_","currentTech","playerDimensions","currentDimensions","videoPlaybackQuality","getVideoPlaybackQuality","setupEme_","setupQualityLevels_","mediaSourceUrl_","IS_IOS","addSourceElement","audioPlaylistLoader","initializedEme","catch","createKeySessions_","didSetupEmeOptions","updatePlaylistByKeyStatus","handleWaitingForKey_","qualityLevels_","playlistControllerEvents","playbackWatcher","VhsSourceHandler","srcObj","setupXhrHooks_","simpleType","getOverrideNative","canUseMsePlayback","defaultOverrideNative","supportsNativeMediaSources","registerSourceHandler","use","registerComponent","getPlugin","registerPlugin"],"mappings":"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","file":"js/chunk-2d0cf52f.2e196d5d.js","sourcesContent":["/*! @name @videojs/http-streaming @version 3.16.2 @license Apache-2.0 */\nimport _extends from '@babel/runtime/helpers/extends';\nimport document from 'global/document';\nimport window$1 from 'global/window';\nimport _resolveUrl from '@videojs/vhs-utils/es/resolve-url.js';\nimport videojs from 'video.js';\nimport { Parser } from 'm3u8-parser';\nimport { isAudioCodec, translateLegacyCodec, codecsFromDefault, parseCodecs, getMimeForCodec, DEFAULT_VIDEO_CODEC, DEFAULT_AUDIO_CODEC, browserSupportsCodec, muxerSupportsCodec } from '@videojs/vhs-utils/es/codecs.js';\nimport { simpleTypeFromSourceType } from '@videojs/vhs-utils/es/media-types.js';\nexport { simpleTypeFromSourceType } from '@videojs/vhs-utils/es/media-types.js';\nimport { isArrayBufferView, concatTypedArrays, stringToBytes, toUint8 } from '@videojs/vhs-utils/es/byte-helpers';\nimport { generateSidxKey, parseUTCTiming, parse, addSidxSegmentsToPlaylist } from 'mpd-parser';\nimport parseSidx from 'mux.js/lib/tools/parse-sidx';\nimport { getId3Offset } from '@videojs/vhs-utils/es/id3-helpers';\nimport { detectContainerForBytes, isLikelyFmp4MediaSegment } from '@videojs/vhs-utils/es/containers';\nimport { ONE_SECOND_IN_TS } from 'mux.js/lib/utils/clock';\n\n/**\n * @file resolve-url.js - Handling how URLs are resolved and manipulated\n */\nconst resolveUrl = _resolveUrl;\n/**\n * If the xhr request was redirected, return the responseURL, otherwise,\n * return the original url.\n *\n * @api private\n *\n * @param {string} url - an url being requested\n * @param {XMLHttpRequest} req - xhr request result\n *\n * @return {string}\n */\n\nconst resolveManifestRedirect = (url, req) => {\n // To understand how the responseURL below is set and generated:\n // - https://fetch.spec.whatwg.org/#concept-response-url\n // - https://fetch.spec.whatwg.org/#atomic-http-redirect-handling\n if (req && req.responseURL && url !== req.responseURL) {\n return req.responseURL;\n }\n\n return url;\n};\n\nconst logger = source => {\n if (videojs.log.debug) {\n return videojs.log.debug.bind(videojs, 'VHS:', `${source} >`);\n }\n\n return function () {};\n};\n\n/**\n * Provides a compatibility layer between Video.js 7 and 8 API changes for VHS.\n */\n/**\n * Delegates to videojs.obj.merge (Video.js 8) or\n * videojs.mergeOptions (Video.js 7).\n */\n\nfunction merge(...args) {\n const context = videojs.obj || videojs;\n const fn = context.merge || context.mergeOptions;\n return fn.apply(context, args);\n}\n/**\n * Delegates to videojs.time.createTimeRanges (Video.js 8) or\n * videojs.createTimeRanges (Video.js 7).\n */\n\nfunction createTimeRanges(...args) {\n const context = videojs.time || videojs;\n const fn = context.createTimeRanges || context.createTimeRanges;\n return fn.apply(context, args);\n}\n/**\n * Converts provided buffered ranges to a descriptive string\n *\n * @param {TimeRanges} buffered - received buffered time ranges\n *\n * @return {string} - descriptive string\n */\n\nfunction bufferedRangesToString(buffered) {\n if (buffered.length === 0) {\n return 'Buffered Ranges are empty';\n }\n\n let bufferedRangesStr = 'Buffered Ranges: \\n';\n\n for (let i = 0; i < buffered.length; i++) {\n const start = buffered.start(i);\n const end = buffered.end(i);\n bufferedRangesStr += `${start} --> ${end}. Duration (${end - start})\\n`;\n }\n\n return bufferedRangesStr;\n}\n\n/**\n * ranges\n *\n * Utilities for working with TimeRanges.\n *\n */\n\nconst TIME_FUDGE_FACTOR = 1 / 30; // Comparisons between time values such as current time and the end of the buffered range\n// can be misleading because of precision differences or when the current media has poorly\n// aligned audio and video, which can cause values to be slightly off from what you would\n// expect. This value is what we consider to be safe to use in such comparisons to account\n// for these scenarios.\n\nconst SAFE_TIME_DELTA = TIME_FUDGE_FACTOR * 3;\n\nconst filterRanges = function (timeRanges, predicate) {\n const results = [];\n let i;\n\n if (timeRanges && timeRanges.length) {\n // Search for ranges that match the predicate\n for (i = 0; i < timeRanges.length; i++) {\n if (predicate(timeRanges.start(i), timeRanges.end(i))) {\n results.push([timeRanges.start(i), timeRanges.end(i)]);\n }\n }\n }\n\n return createTimeRanges(results);\n};\n/**\n * Attempts to find the buffered TimeRange that contains the specified\n * time.\n *\n * @param {TimeRanges} buffered - the TimeRanges object to query\n * @param {number} time - the time to filter on.\n * @return {TimeRanges} a new TimeRanges object\n */\n\n\nconst findRange = function (buffered, time) {\n return filterRanges(buffered, function (start, end) {\n return start - SAFE_TIME_DELTA <= time && end + SAFE_TIME_DELTA >= time;\n });\n};\n/**\n * Returns the TimeRanges that begin later than the specified time.\n *\n * @param {TimeRanges} timeRanges - the TimeRanges object to query\n * @param {number} time - the time to filter on.\n * @return {TimeRanges} a new TimeRanges object.\n */\n\nconst findNextRange = function (timeRanges, time) {\n return filterRanges(timeRanges, function (start) {\n return start - TIME_FUDGE_FACTOR >= time;\n });\n};\n/**\n * Returns gaps within a list of TimeRanges\n *\n * @param {TimeRanges} buffered - the TimeRanges object\n * @return {TimeRanges} a TimeRanges object of gaps\n */\n\nconst findGaps = function (buffered) {\n if (buffered.length < 2) {\n return createTimeRanges();\n }\n\n const ranges = [];\n\n for (let i = 1; i < buffered.length; i++) {\n const start = buffered.end(i - 1);\n const end = buffered.start(i);\n ranges.push([start, end]);\n }\n\n return createTimeRanges(ranges);\n};\n/**\n * Calculate the intersection of two TimeRanges\n *\n * @param {TimeRanges} bufferA\n * @param {TimeRanges} bufferB\n * @return {TimeRanges} The interesection of `bufferA` with `bufferB`\n */\n\nconst bufferIntersection = function (bufferA, bufferB) {\n let start = null;\n let end = null;\n let arity = 0;\n const extents = [];\n const ranges = [];\n\n if (!bufferA || !bufferA.length || !bufferB || !bufferB.length) {\n return createTimeRanges();\n } // Handle the case where we have both buffers and create an\n // intersection of the two\n\n\n let count = bufferA.length; // A) Gather up all start and end times\n\n while (count--) {\n extents.push({\n time: bufferA.start(count),\n type: 'start'\n });\n extents.push({\n time: bufferA.end(count),\n type: 'end'\n });\n }\n\n count = bufferB.length;\n\n while (count--) {\n extents.push({\n time: bufferB.start(count),\n type: 'start'\n });\n extents.push({\n time: bufferB.end(count),\n type: 'end'\n });\n } // B) Sort them by time\n\n\n extents.sort(function (a, b) {\n return a.time - b.time;\n }); // C) Go along one by one incrementing arity for start and decrementing\n // arity for ends\n\n for (count = 0; count < extents.length; count++) {\n if (extents[count].type === 'start') {\n arity++; // D) If arity is ever incremented to 2 we are entering an\n // overlapping range\n\n if (arity === 2) {\n start = extents[count].time;\n }\n } else if (extents[count].type === 'end') {\n arity--; // E) If arity is ever decremented to 1 we leaving an\n // overlapping range\n\n if (arity === 1) {\n end = extents[count].time;\n }\n } // F) Record overlapping ranges\n\n\n if (start !== null && end !== null) {\n ranges.push([start, end]);\n start = null;\n end = null;\n }\n }\n\n return createTimeRanges(ranges);\n};\n/**\n * Gets a human readable string for a TimeRange\n *\n * @param {TimeRange} range\n * @return {string} a human readable string\n */\n\nconst printableRange = range => {\n const strArr = [];\n\n if (!range || !range.length) {\n return '';\n }\n\n for (let i = 0; i < range.length; i++) {\n strArr.push(range.start(i) + ' => ' + range.end(i));\n }\n\n return strArr.join(', ');\n};\n/**\n * Calculates the amount of time left in seconds until the player hits the end of the\n * buffer and causes a rebuffer\n *\n * @param {TimeRange} buffered\n * The state of the buffer\n * @param {Numnber} currentTime\n * The current time of the player\n * @param {number} playbackRate\n * The current playback rate of the player. Defaults to 1.\n * @return {number}\n * Time until the player has to start rebuffering in seconds.\n * @function timeUntilRebuffer\n */\n\nconst timeUntilRebuffer = function (buffered, currentTime, playbackRate = 1) {\n const bufferedEnd = buffered.length ? buffered.end(buffered.length - 1) : 0;\n return (bufferedEnd - currentTime) / playbackRate;\n};\n/**\n * Converts a TimeRanges object into an array representation\n *\n * @param {TimeRanges} timeRanges\n * @return {Array}\n */\n\nconst timeRangesToArray = timeRanges => {\n const timeRangesList = [];\n\n for (let i = 0; i < timeRanges.length; i++) {\n timeRangesList.push({\n start: timeRanges.start(i),\n end: timeRanges.end(i)\n });\n }\n\n return timeRangesList;\n};\n/**\n * Determines if two time range objects are different.\n *\n * @param {TimeRange} a\n * the first time range object to check\n *\n * @param {TimeRange} b\n * the second time range object to check\n *\n * @return {Boolean}\n * Whether the time range objects differ\n */\n\nconst isRangeDifferent = function (a, b) {\n // same object\n if (a === b) {\n return false;\n } // one or the other is undefined\n\n\n if (!a && b || !b && a) {\n return true;\n } // length is different\n\n\n if (a.length !== b.length) {\n return true;\n } // see if any start/end pair is different\n\n\n for (let i = 0; i < a.length; i++) {\n if (a.start(i) !== b.start(i) || a.end(i) !== b.end(i)) {\n return true;\n }\n } // if the length and every pair is the same\n // this is the same time range\n\n\n return false;\n};\nconst lastBufferedEnd = function (a) {\n if (!a || !a.length || !a.end) {\n return;\n }\n\n return a.end(a.length - 1);\n};\n/**\n * A utility function to add up the amount of time in a timeRange\n * after a specified startTime.\n * ie:[[0, 10], [20, 40], [50, 60]] with a startTime 0\n * would return 40 as there are 40s seconds after 0 in the timeRange\n *\n * @param {TimeRange} range\n * The range to check against\n * @param {number} startTime\n * The time in the time range that you should start counting from\n *\n * @return {number}\n * The number of seconds in the buffer passed the specified time.\n */\n\nconst timeAheadOf = function (range, startTime) {\n let time = 0;\n\n if (!range || !range.length) {\n return time;\n }\n\n for (let i = 0; i < range.length; i++) {\n const start = range.start(i);\n const end = range.end(i); // startTime is after this range entirely\n\n if (startTime > end) {\n continue;\n } // startTime is within this range\n\n\n if (startTime > start && startTime <= end) {\n time += end - startTime;\n continue;\n } // startTime is before this range.\n\n\n time += end - start;\n }\n\n return time;\n};\n\n/**\n * @file playlist.js\n *\n * Playlist related utilities.\n */\n/**\n * Get the duration of a segment, with special cases for\n * llhls segments that do not have a duration yet.\n *\n * @param {Object} playlist\n * the playlist that the segment belongs to.\n * @param {Object} segment\n * the segment to get a duration for.\n *\n * @return {number}\n * the segment duration\n */\n\nconst segmentDurationWithParts = (playlist, segment) => {\n // if this isn't a preload segment\n // then we will have a segment duration that is accurate.\n if (!segment.preload) {\n return segment.duration;\n } // otherwise we have to add up parts and preload hints\n // to get an up to date duration.\n\n\n let result = 0;\n (segment.parts || []).forEach(function (p) {\n result += p.duration;\n }); // for preload hints we have to use partTargetDuration\n // as they won't even have a duration yet.\n\n (segment.preloadHints || []).forEach(function (p) {\n if (p.type === 'PART') {\n result += playlist.partTargetDuration;\n }\n });\n return result;\n};\n/**\n * A function to get a combined list of parts and segments with durations\n * and indexes.\n *\n * @param {Playlist} playlist the playlist to get the list for.\n *\n * @return {Array} The part/segment list.\n */\n\nconst getPartsAndSegments = playlist => (playlist.segments || []).reduce((acc, segment, si) => {\n if (segment.parts) {\n segment.parts.forEach(function (part, pi) {\n acc.push({\n duration: part.duration,\n segmentIndex: si,\n partIndex: pi,\n part,\n segment\n });\n });\n } else {\n acc.push({\n duration: segment.duration,\n segmentIndex: si,\n partIndex: null,\n segment,\n part: null\n });\n }\n\n return acc;\n}, []);\nconst getLastParts = media => {\n const lastSegment = media.segments && media.segments.length && media.segments[media.segments.length - 1];\n return lastSegment && lastSegment.parts || [];\n};\nconst getKnownPartCount = ({\n preloadSegment\n}) => {\n if (!preloadSegment) {\n return;\n }\n\n const {\n parts,\n preloadHints\n } = preloadSegment;\n let partCount = (preloadHints || []).reduce((count, hint) => count + (hint.type === 'PART' ? 1 : 0), 0);\n partCount += parts && parts.length ? parts.length : 0;\n return partCount;\n};\n/**\n * Get the number of seconds to delay from the end of a\n * live playlist.\n *\n * @param {Playlist} main the main playlist\n * @param {Playlist} media the media playlist\n * @return {number} the hold back in seconds.\n */\n\nconst liveEdgeDelay = (main, media) => {\n if (media.endList) {\n return 0;\n } // dash suggestedPresentationDelay trumps everything\n\n\n if (main && main.suggestedPresentationDelay) {\n return main.suggestedPresentationDelay;\n }\n\n const hasParts = getLastParts(media).length > 0; // look for \"part\" delays from ll-hls first\n\n if (hasParts && media.serverControl && media.serverControl.partHoldBack) {\n return media.serverControl.partHoldBack;\n } else if (hasParts && media.partTargetDuration) {\n return media.partTargetDuration * 3; // finally look for full segment delays\n } else if (media.serverControl && media.serverControl.holdBack) {\n return media.serverControl.holdBack;\n } else if (media.targetDuration) {\n return media.targetDuration * 3;\n }\n\n return 0;\n};\n/**\n * walk backward until we find a duration we can use\n * or return a failure\n *\n * @param {Playlist} playlist the playlist to walk through\n * @param {Number} endSequence the mediaSequence to stop walking on\n */\n\nconst backwardDuration = function (playlist, endSequence) {\n let result = 0;\n let i = endSequence - playlist.mediaSequence; // if a start time is available for segment immediately following\n // the interval, use it\n\n let segment = playlist.segments[i]; // Walk backward until we find the latest segment with timeline\n // information that is earlier than endSequence\n\n if (segment) {\n if (typeof segment.start !== 'undefined') {\n return {\n result: segment.start,\n precise: true\n };\n }\n\n if (typeof segment.end !== 'undefined') {\n return {\n result: segment.end - segment.duration,\n precise: true\n };\n }\n }\n\n while (i--) {\n segment = playlist.segments[i];\n\n if (typeof segment.end !== 'undefined') {\n return {\n result: result + segment.end,\n precise: true\n };\n }\n\n result += segmentDurationWithParts(playlist, segment);\n\n if (typeof segment.start !== 'undefined') {\n return {\n result: result + segment.start,\n precise: true\n };\n }\n }\n\n return {\n result,\n precise: false\n };\n};\n/**\n * walk forward until we find a duration we can use\n * or return a failure\n *\n * @param {Playlist} playlist the playlist to walk through\n * @param {number} endSequence the mediaSequence to stop walking on\n */\n\n\nconst forwardDuration = function (playlist, endSequence) {\n let result = 0;\n let segment;\n let i = endSequence - playlist.mediaSequence; // Walk forward until we find the earliest segment with timeline\n // information\n\n for (; i < playlist.segments.length; i++) {\n segment = playlist.segments[i];\n\n if (typeof segment.start !== 'undefined') {\n return {\n result: segment.start - result,\n precise: true\n };\n }\n\n result += segmentDurationWithParts(playlist, segment);\n\n if (typeof segment.end !== 'undefined') {\n return {\n result: segment.end - result,\n precise: true\n };\n }\n } // indicate we didn't find a useful duration estimate\n\n\n return {\n result: -1,\n precise: false\n };\n};\n/**\n * Calculate the media duration from the segments associated with a\n * playlist. The duration of a subinterval of the available segments\n * may be calculated by specifying an end index.\n *\n * @param {Object} playlist a media playlist object\n * @param {number=} endSequence an exclusive upper boundary\n * for the playlist. Defaults to playlist length.\n * @param {number} expired the amount of time that has dropped\n * off the front of the playlist in a live scenario\n * @return {number} the duration between the first available segment\n * and end index.\n */\n\n\nconst intervalDuration = function (playlist, endSequence, expired) {\n if (typeof endSequence === 'undefined') {\n endSequence = playlist.mediaSequence + playlist.segments.length;\n }\n\n if (endSequence < playlist.mediaSequence) {\n return 0;\n } // do a backward walk to estimate the duration\n\n\n const backward = backwardDuration(playlist, endSequence);\n\n if (backward.precise) {\n // if we were able to base our duration estimate on timing\n // information provided directly from the Media Source, return\n // it\n return backward.result;\n } // walk forward to see if a precise duration estimate can be made\n // that way\n\n\n const forward = forwardDuration(playlist, endSequence);\n\n if (forward.precise) {\n // we found a segment that has been buffered and so it's\n // position is known precisely\n return forward.result;\n } // return the less-precise, playlist-based duration estimate\n\n\n return backward.result + expired;\n};\n/**\n * Calculates the duration of a playlist. If a start and end index\n * are specified, the duration will be for the subset of the media\n * timeline between those two indices. The total duration for live\n * playlists is always Infinity.\n *\n * @param {Object} playlist a media playlist object\n * @param {number=} endSequence an exclusive upper\n * boundary for the playlist. Defaults to the playlist media\n * sequence number plus its length.\n * @param {number=} expired the amount of time that has\n * dropped off the front of the playlist in a live scenario\n * @return {number} the duration between the start index and end\n * index.\n */\n\n\nconst duration = function (playlist, endSequence, expired) {\n if (!playlist) {\n return 0;\n }\n\n if (typeof expired !== 'number') {\n expired = 0;\n } // if a slice of the total duration is not requested, use\n // playlist-level duration indicators when they're present\n\n\n if (typeof endSequence === 'undefined') {\n // if present, use the duration specified in the playlist\n if (playlist.totalDuration) {\n return playlist.totalDuration;\n } // duration should be Infinity for live playlists\n\n\n if (!playlist.endList) {\n return window$1.Infinity;\n }\n } // calculate the total duration based on the segment durations\n\n\n return intervalDuration(playlist, endSequence, expired);\n};\n/**\n * Calculate the time between two indexes in the current playlist\n * neight the start- nor the end-index need to be within the current\n * playlist in which case, the targetDuration of the playlist is used\n * to approximate the durations of the segments\n *\n * @param {Array} options.durationList list to iterate over for durations.\n * @param {number} options.defaultDuration duration to use for elements before or after the durationList\n * @param {number} options.startIndex partsAndSegments index to start\n * @param {number} options.endIndex partsAndSegments index to end.\n * @return {number} the number of seconds between startIndex and endIndex\n */\n\nconst sumDurations = function ({\n defaultDuration,\n durationList,\n startIndex,\n endIndex\n}) {\n let durations = 0;\n\n if (startIndex > endIndex) {\n [startIndex, endIndex] = [endIndex, startIndex];\n }\n\n if (startIndex < 0) {\n for (let i = startIndex; i < Math.min(0, endIndex); i++) {\n durations += defaultDuration;\n }\n\n startIndex = 0;\n }\n\n for (let i = startIndex; i < endIndex; i++) {\n durations += durationList[i].duration;\n }\n\n return durations;\n};\n/**\n * Calculates the playlist end time\n *\n * @param {Object} playlist a media playlist object\n * @param {number=} expired the amount of time that has\n * dropped off the front of the playlist in a live scenario\n * @param {boolean|false} useSafeLiveEnd a boolean value indicating whether or not the\n * playlist end calculation should consider the safe live end\n * (truncate the playlist end by three segments). This is normally\n * used for calculating the end of the playlist's seekable range.\n * This takes into account the value of liveEdgePadding.\n * Setting liveEdgePadding to 0 is equivalent to setting this to false.\n * @param {number} liveEdgePadding a number indicating how far from the end of the playlist we should be in seconds.\n * If this is provided, it is used in the safe live end calculation.\n * Setting useSafeLiveEnd=false or liveEdgePadding=0 are equivalent.\n * Corresponds to suggestedPresentationDelay in DASH manifests.\n * @return {number} the end time of playlist\n * @function playlistEnd\n */\n\nconst playlistEnd = function (playlist, expired, useSafeLiveEnd, liveEdgePadding) {\n if (!playlist || !playlist.segments) {\n return null;\n }\n\n if (playlist.endList) {\n return duration(playlist);\n }\n\n if (expired === null) {\n return null;\n }\n\n expired = expired || 0;\n let lastSegmentEndTime = intervalDuration(playlist, playlist.mediaSequence + playlist.segments.length, expired);\n\n if (useSafeLiveEnd) {\n liveEdgePadding = typeof liveEdgePadding === 'number' ? liveEdgePadding : liveEdgeDelay(null, playlist);\n lastSegmentEndTime -= liveEdgePadding;\n } // don't return a time less than zero\n\n\n return Math.max(0, lastSegmentEndTime);\n};\n/**\n * Calculates the interval of time that is currently seekable in a\n * playlist. The returned time ranges are relative to the earliest\n * moment in the specified playlist that is still available. A full\n * seekable implementation for live streams would need to offset\n * these values by the duration of content that has expired from the\n * stream.\n *\n * @param {Object} playlist a media playlist object\n * dropped off the front of the playlist in a live scenario\n * @param {number=} expired the amount of time that has\n * dropped off the front of the playlist in a live scenario\n * @param {number} liveEdgePadding how far from the end of the playlist we should be in seconds.\n * Corresponds to suggestedPresentationDelay in DASH manifests.\n * @return {TimeRanges} the periods of time that are valid targets\n * for seeking\n */\n\nconst seekable = function (playlist, expired, liveEdgePadding) {\n const useSafeLiveEnd = true;\n const seekableStart = expired || 0;\n let seekableEnd = playlistEnd(playlist, expired, useSafeLiveEnd, liveEdgePadding);\n\n if (seekableEnd === null) {\n return createTimeRanges();\n } // Clamp seekable end since it can not be less than the seekable start\n\n\n if (seekableEnd < seekableStart) {\n seekableEnd = seekableStart;\n }\n\n return createTimeRanges(seekableStart, seekableEnd);\n};\n/**\n * Determine the index and estimated starting time of the segment that\n * contains a specified playback position in a media playlist.\n *\n * @param {Object} options.playlist the media playlist to query\n * @param {number} options.currentTime The number of seconds since the earliest\n * possible position to determine the containing segment for\n * @param {number} options.startTime the time when the segment/part starts\n * @param {number} options.startingSegmentIndex the segment index to start looking at.\n * @param {number?} [options.startingPartIndex] the part index to look at within the segment.\n *\n * @return {Object} an object with partIndex, segmentIndex, and startTime.\n */\n\nconst getMediaInfoForTime = function ({\n playlist,\n currentTime,\n startingSegmentIndex,\n startingPartIndex,\n startTime,\n exactManifestTimings\n}) {\n let time = currentTime - startTime;\n const partsAndSegments = getPartsAndSegments(playlist);\n let startIndex = 0;\n\n for (let i = 0; i < partsAndSegments.length; i++) {\n const partAndSegment = partsAndSegments[i];\n\n if (startingSegmentIndex !== partAndSegment.segmentIndex) {\n continue;\n } // skip this if part index does not match.\n\n\n if (typeof startingPartIndex === 'number' && typeof partAndSegment.partIndex === 'number' && startingPartIndex !== partAndSegment.partIndex) {\n continue;\n }\n\n startIndex = i;\n break;\n }\n\n if (time < 0) {\n // Walk backward from startIndex in the playlist, adding durations\n // until we find a segment that contains `time` and return it\n if (startIndex > 0) {\n for (let i = startIndex - 1; i >= 0; i--) {\n const partAndSegment = partsAndSegments[i];\n time += partAndSegment.duration;\n\n if (exactManifestTimings) {\n if (time < 0) {\n continue;\n }\n } else if (time + TIME_FUDGE_FACTOR <= 0) {\n continue;\n }\n\n return {\n partIndex: partAndSegment.partIndex,\n segmentIndex: partAndSegment.segmentIndex,\n startTime: startTime - sumDurations({\n defaultDuration: playlist.targetDuration,\n durationList: partsAndSegments,\n startIndex,\n endIndex: i\n })\n };\n }\n } // We were unable to find a good segment within the playlist\n // so select the first segment\n\n\n return {\n partIndex: partsAndSegments[0] && partsAndSegments[0].partIndex || null,\n segmentIndex: partsAndSegments[0] && partsAndSegments[0].segmentIndex || 0,\n startTime: currentTime\n };\n } // When startIndex is negative, we first walk forward to first segment\n // adding target durations. If we \"run out of time\" before getting to\n // the first segment, return the first segment\n\n\n if (startIndex < 0) {\n for (let i = startIndex; i < 0; i++) {\n time -= playlist.targetDuration;\n\n if (time < 0) {\n return {\n partIndex: partsAndSegments[0] && partsAndSegments[0].partIndex || null,\n segmentIndex: partsAndSegments[0] && partsAndSegments[0].segmentIndex || 0,\n startTime: currentTime\n };\n }\n }\n\n startIndex = 0;\n } // Walk forward from startIndex in the playlist, subtracting durations\n // until we find a segment that contains `time` and return it\n\n\n for (let i = startIndex; i < partsAndSegments.length; i++) {\n const partAndSegment = partsAndSegments[i];\n time -= partAndSegment.duration;\n const canUseFudgeFactor = partAndSegment.duration > TIME_FUDGE_FACTOR;\n const isExactlyAtTheEnd = time === 0;\n const isExtremelyCloseToTheEnd = canUseFudgeFactor && time + TIME_FUDGE_FACTOR >= 0;\n\n if (isExactlyAtTheEnd || isExtremelyCloseToTheEnd) {\n // 1) We are exactly at the end of the current segment.\n // 2) We are extremely close to the end of the current segment (The difference is less than 1 / 30).\n // We may encounter this situation when\n // we don't have exact match between segment duration info in the manifest and the actual duration of the segment\n // For example:\n // We appended 3 segments 10 seconds each, meaning we should have 30 sec buffered,\n // but we the actual buffered is 29.99999\n //\n // In both cases:\n // if we passed current time -> it means that we already played current segment\n // if we passed buffered.end -> it means that this segment is already loaded and buffered\n // we should select the next segment if we have one:\n if (i !== partsAndSegments.length - 1) {\n continue;\n }\n }\n\n if (exactManifestTimings) {\n if (time > 0) {\n continue;\n }\n } else if (time - TIME_FUDGE_FACTOR >= 0) {\n continue;\n }\n\n return {\n partIndex: partAndSegment.partIndex,\n segmentIndex: partAndSegment.segmentIndex,\n startTime: startTime + sumDurations({\n defaultDuration: playlist.targetDuration,\n durationList: partsAndSegments,\n startIndex,\n endIndex: i\n })\n };\n } // We are out of possible candidates so load the last one...\n\n\n return {\n segmentIndex: partsAndSegments[partsAndSegments.length - 1].segmentIndex,\n partIndex: partsAndSegments[partsAndSegments.length - 1].partIndex,\n startTime: currentTime\n };\n};\n/**\n * Check whether the playlist is excluded or not.\n *\n * @param {Object} playlist the media playlist object\n * @return {boolean} whether the playlist is excluded or not\n * @function isExcluded\n */\n\nconst isExcluded = function (playlist) {\n return playlist.excludeUntil && playlist.excludeUntil > Date.now();\n};\n/**\n * Check whether the playlist is compatible with current playback configuration or has\n * been excluded permanently for being incompatible.\n *\n * @param {Object} playlist the media playlist object\n * @return {boolean} whether the playlist is incompatible or not\n * @function isIncompatible\n */\n\nconst isIncompatible = function (playlist) {\n return playlist.excludeUntil && playlist.excludeUntil === Infinity;\n};\n/**\n * Check whether the playlist is enabled or not.\n *\n * @param {Object} playlist the media playlist object\n * @return {boolean} whether the playlist is enabled or not\n * @function isEnabled\n */\n\nconst isEnabled = function (playlist) {\n const excluded = isExcluded(playlist);\n return !playlist.disabled && !excluded;\n};\n/**\n * Check whether the playlist has been manually disabled through the representations api.\n *\n * @param {Object} playlist the media playlist object\n * @return {boolean} whether the playlist is disabled manually or not\n * @function isDisabled\n */\n\nconst isDisabled = function (playlist) {\n return playlist.disabled;\n};\n/**\n * Returns whether the current playlist is an AES encrypted HLS stream\n *\n * @return {boolean} true if it's an AES encrypted HLS stream\n */\n\nconst isAes = function (media) {\n for (let i = 0; i < media.segments.length; i++) {\n if (media.segments[i].key) {\n return true;\n }\n }\n\n return false;\n};\n/**\n * Checks if the playlist has a value for the specified attribute\n *\n * @param {string} attr\n * Attribute to check for\n * @param {Object} playlist\n * The media playlist object\n * @return {boolean}\n * Whether the playlist contains a value for the attribute or not\n * @function hasAttribute\n */\n\nconst hasAttribute = function (attr, playlist) {\n return playlist.attributes && playlist.attributes[attr];\n};\n/**\n * Estimates the time required to complete a segment download from the specified playlist\n *\n * @param {number} segmentDuration\n * Duration of requested segment\n * @param {number} bandwidth\n * Current measured bandwidth of the player\n * @param {Object} playlist\n * The media playlist object\n * @param {number=} bytesReceived\n * Number of bytes already received for the request. Defaults to 0\n * @return {number|NaN}\n * The estimated time to request the segment. NaN if bandwidth information for\n * the given playlist is unavailable\n * @function estimateSegmentRequestTime\n */\n\nconst estimateSegmentRequestTime = function (segmentDuration, bandwidth, playlist, bytesReceived = 0) {\n if (!hasAttribute('BANDWIDTH', playlist)) {\n return NaN;\n }\n\n const size = segmentDuration * playlist.attributes.BANDWIDTH;\n return (size - bytesReceived * 8) / bandwidth;\n};\n/*\n * Returns whether the current playlist is the lowest rendition\n *\n * @return {Boolean} true if on lowest rendition\n */\n\nconst isLowestEnabledRendition = (main, media) => {\n if (main.playlists.length === 1) {\n return true;\n }\n\n const currentBandwidth = media.attributes.BANDWIDTH || Number.MAX_VALUE;\n return main.playlists.filter(playlist => {\n if (!isEnabled(playlist)) {\n return false;\n }\n\n return (playlist.attributes.BANDWIDTH || 0) < currentBandwidth;\n }).length === 0;\n};\nconst playlistMatch = (a, b) => {\n // both playlits are null\n // or only one playlist is non-null\n // no match\n if (!a && !b || !a && b || a && !b) {\n return false;\n } // playlist objects are the same, match\n\n\n if (a === b) {\n return true;\n } // first try to use id as it should be the most\n // accurate\n\n\n if (a.id && b.id && a.id === b.id) {\n return true;\n } // next try to use reslovedUri as it should be the\n // second most accurate.\n\n\n if (a.resolvedUri && b.resolvedUri && a.resolvedUri === b.resolvedUri) {\n return true;\n } // finally try to use uri as it should be accurate\n // but might miss a few cases for relative uris\n\n\n if (a.uri && b.uri && a.uri === b.uri) {\n return true;\n }\n\n return false;\n};\n\nconst someAudioVariant = function (main, callback) {\n const AUDIO = main && main.mediaGroups && main.mediaGroups.AUDIO || {};\n let found = false;\n\n for (const groupName in AUDIO) {\n for (const label in AUDIO[groupName]) {\n found = callback(AUDIO[groupName][label]);\n\n if (found) {\n break;\n }\n }\n\n if (found) {\n break;\n }\n }\n\n return !!found;\n};\n\nconst isAudioOnly = main => {\n // we are audio only if we have no main playlists but do\n // have media group playlists.\n if (!main || !main.playlists || !main.playlists.length) {\n // without audio variants or playlists this\n // is not an audio only main.\n const found = someAudioVariant(main, variant => variant.playlists && variant.playlists.length || variant.uri);\n return found;\n } // if every playlist has only an audio codec it is audio only\n\n\n for (let i = 0; i < main.playlists.length; i++) {\n const playlist = main.playlists[i];\n const CODECS = playlist.attributes && playlist.attributes.CODECS; // all codecs are audio, this is an audio playlist.\n\n if (CODECS && CODECS.split(',').every(c => isAudioCodec(c))) {\n continue;\n } // playlist is in an audio group it is audio only\n\n\n const found = someAudioVariant(main, variant => playlistMatch(playlist, variant));\n\n if (found) {\n continue;\n } // if we make it here this playlist isn't audio and we\n // are not audio only\n\n\n return false;\n } // if we make it past every playlist without returning, then\n // this is an audio only playlist.\n\n\n return true;\n}; // exports\n\nvar Playlist = {\n liveEdgeDelay,\n duration,\n seekable,\n getMediaInfoForTime,\n isEnabled,\n isDisabled,\n isExcluded,\n isIncompatible,\n playlistEnd,\n isAes,\n hasAttribute,\n estimateSegmentRequestTime,\n isLowestEnabledRendition,\n isAudioOnly,\n playlistMatch,\n segmentDurationWithParts\n};\n\nconst {\n log\n} = videojs;\nconst createPlaylistID = (index, uri) => {\n return `${index}-${uri}`;\n}; // default function for creating a group id\n\nconst groupID = (type, group, label) => {\n return `placeholder-uri-${type}-${group}-${label}`;\n};\n/**\n * Parses a given m3u8 playlist\n *\n * @param {Function} [onwarn]\n * a function to call when the parser triggers a warning event.\n * @param {Function} [oninfo]\n * a function to call when the parser triggers an info event.\n * @param {string} manifestString\n * The downloaded manifest string\n * @param {Object[]} [customTagParsers]\n * An array of custom tag parsers for the m3u8-parser instance\n * @param {Object[]} [customTagMappers]\n * An array of custom tag mappers for the m3u8-parser instance\n * @param {boolean} [llhls]\n * Whether to keep ll-hls features in the manifest after parsing.\n * @return {Object}\n * The manifest object\n */\n\nconst parseManifest = ({\n onwarn,\n oninfo,\n manifestString,\n customTagParsers = [],\n customTagMappers = [],\n llhls\n}) => {\n const parser = new Parser();\n\n if (onwarn) {\n parser.on('warn', onwarn);\n }\n\n if (oninfo) {\n parser.on('info', oninfo);\n }\n\n customTagParsers.forEach(customParser => parser.addParser(customParser));\n customTagMappers.forEach(mapper => parser.addTagMapper(mapper));\n parser.push(manifestString);\n parser.end();\n const manifest = parser.manifest; // remove llhls features from the parsed manifest\n // if we don't want llhls support.\n\n if (!llhls) {\n ['preloadSegment', 'skip', 'serverControl', 'renditionReports', 'partInf', 'partTargetDuration'].forEach(function (k) {\n if (manifest.hasOwnProperty(k)) {\n delete manifest[k];\n }\n });\n\n if (manifest.segments) {\n manifest.segments.forEach(function (segment) {\n ['parts', 'preloadHints'].forEach(function (k) {\n if (segment.hasOwnProperty(k)) {\n delete segment[k];\n }\n });\n });\n }\n }\n\n if (!manifest.targetDuration) {\n let targetDuration = 10;\n\n if (manifest.segments && manifest.segments.length) {\n targetDuration = manifest.segments.reduce((acc, s) => Math.max(acc, s.duration), 0);\n }\n\n if (onwarn) {\n onwarn({\n message: `manifest has no targetDuration defaulting to ${targetDuration}`\n });\n }\n\n manifest.targetDuration = targetDuration;\n }\n\n const parts = getLastParts(manifest);\n\n if (parts.length && !manifest.partTargetDuration) {\n const partTargetDuration = parts.reduce((acc, p) => Math.max(acc, p.duration), 0);\n\n if (onwarn) {\n onwarn({\n message: `manifest has no partTargetDuration defaulting to ${partTargetDuration}`\n });\n log.error('LL-HLS manifest has parts but lacks required #EXT-X-PART-INF:PART-TARGET value. See https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-09#section-4.4.3.7. Playback is not guaranteed.');\n }\n\n manifest.partTargetDuration = partTargetDuration;\n }\n\n return manifest;\n};\n/**\n * Loops through all supported media groups in main and calls the provided\n * callback for each group\n *\n * @param {Object} main\n * The parsed main manifest object\n * @param {Function} callback\n * Callback to call for each media group\n */\n\nconst forEachMediaGroup = (main, callback) => {\n if (!main.mediaGroups) {\n return;\n }\n\n ['AUDIO', 'SUBTITLES'].forEach(mediaType => {\n if (!main.mediaGroups[mediaType]) {\n return;\n }\n\n for (const groupKey in main.mediaGroups[mediaType]) {\n for (const labelKey in main.mediaGroups[mediaType][groupKey]) {\n const mediaProperties = main.mediaGroups[mediaType][groupKey][labelKey];\n callback(mediaProperties, mediaType, groupKey, labelKey);\n }\n }\n });\n};\n/**\n * Adds properties and attributes to the playlist to keep consistent functionality for\n * playlists throughout VHS.\n *\n * @param {Object} config\n * Arguments object\n * @param {Object} config.playlist\n * The media playlist\n * @param {string} [config.uri]\n * The uri to the media playlist (if media playlist is not from within a main\n * playlist)\n * @param {string} id\n * ID to use for the playlist\n */\n\nconst setupMediaPlaylist = ({\n playlist,\n uri,\n id\n}) => {\n playlist.id = id;\n playlist.playlistErrors_ = 0;\n\n if (uri) {\n // For media playlists, m3u8-parser does not have access to a URI, as HLS media\n // playlists do not contain their own source URI, but one is needed for consistency in\n // VHS.\n playlist.uri = uri;\n } // For HLS main playlists, even though certain attributes MUST be defined, the\n // stream may still be played without them.\n // For HLS media playlists, m3u8-parser does not attach an attributes object to the\n // manifest.\n //\n // To avoid undefined reference errors through the project, and make the code easier\n // to write/read, add an empty attributes object for these cases.\n\n\n playlist.attributes = playlist.attributes || {};\n};\n/**\n * Adds ID, resolvedUri, and attributes properties to each playlist of the main, where\n * necessary. In addition, creates playlist IDs for each playlist and adds playlist ID to\n * playlist references to the playlists array.\n *\n * @param {Object} main\n * The main playlist\n */\n\nconst setupMediaPlaylists = main => {\n let i = main.playlists.length;\n\n while (i--) {\n const playlist = main.playlists[i];\n setupMediaPlaylist({\n playlist,\n id: createPlaylistID(i, playlist.uri)\n });\n playlist.resolvedUri = resolveUrl(main.uri, playlist.uri);\n main.playlists[playlist.id] = playlist; // URI reference added for backwards compatibility\n\n main.playlists[playlist.uri] = playlist; // Although the spec states an #EXT-X-STREAM-INF tag MUST have a BANDWIDTH attribute,\n // the stream can be played without it. Although an attributes property may have been\n // added to the playlist to prevent undefined references, issue a warning to fix the\n // manifest.\n\n if (!playlist.attributes.BANDWIDTH) {\n log.warn('Invalid playlist STREAM-INF detected. Missing BANDWIDTH attribute.');\n }\n }\n};\n/**\n * Adds resolvedUri properties to each media group.\n *\n * @param {Object} main\n * The main playlist\n */\n\nconst resolveMediaGroupUris = main => {\n forEachMediaGroup(main, properties => {\n if (properties.uri) {\n properties.resolvedUri = resolveUrl(main.uri, properties.uri);\n }\n });\n};\n/**\n * Creates a main playlist wrapper to insert a sole media playlist into.\n *\n * @param {Object} media\n * Media playlist\n * @param {string} uri\n * The media URI\n *\n * @return {Object}\n * main playlist\n */\n\nconst mainForMedia = (media, uri) => {\n const id = createPlaylistID(0, uri);\n const main = {\n mediaGroups: {\n 'AUDIO': {},\n 'VIDEO': {},\n 'CLOSED-CAPTIONS': {},\n 'SUBTITLES': {}\n },\n uri: window$1.location.href,\n resolvedUri: window$1.location.href,\n playlists: [{\n uri,\n id,\n resolvedUri: uri,\n // m3u8-parser does not attach an attributes property to media playlists so make\n // sure that the property is attached to avoid undefined reference errors\n attributes: {}\n }]\n }; // set up ID reference\n\n main.playlists[id] = main.playlists[0]; // URI reference added for backwards compatibility\n\n main.playlists[uri] = main.playlists[0];\n return main;\n};\n/**\n * Does an in-place update of the main manifest to add updated playlist URI references\n * as well as other properties needed by VHS that aren't included by the parser.\n *\n * @param {Object} main\n * main manifest object\n * @param {string} uri\n * The source URI\n * @param {function} createGroupID\n * A function to determine how to create the groupID for mediaGroups\n */\n\nconst addPropertiesToMain = (main, uri, createGroupID = groupID) => {\n main.uri = uri;\n\n for (let i = 0; i < main.playlists.length; i++) {\n if (!main.playlists[i].uri) {\n // Set up phony URIs for the playlists since playlists are referenced by their URIs\n // throughout VHS, but some formats (e.g., DASH) don't have external URIs\n // TODO: consider adding dummy URIs in mpd-parser\n const phonyUri = `placeholder-uri-${i}`;\n main.playlists[i].uri = phonyUri;\n }\n }\n\n const audioOnlyMain = isAudioOnly(main);\n forEachMediaGroup(main, (properties, mediaType, groupKey, labelKey) => {\n // add a playlist array under properties\n if (!properties.playlists || !properties.playlists.length) {\n // If the manifest is audio only and this media group does not have a uri, check\n // if the media group is located in the main list of playlists. If it is, don't add\n // placeholder properties as it shouldn't be considered an alternate audio track.\n if (audioOnlyMain && mediaType === 'AUDIO' && !properties.uri) {\n for (let i = 0; i < main.playlists.length; i++) {\n const p = main.playlists[i];\n\n if (p.attributes && p.attributes.AUDIO && p.attributes.AUDIO === groupKey) {\n return;\n }\n }\n }\n\n properties.playlists = [_extends({}, properties)];\n }\n\n properties.playlists.forEach(function (p, i) {\n const groupId = createGroupID(mediaType, groupKey, labelKey, p);\n const id = createPlaylistID(i, groupId);\n\n if (p.uri) {\n p.resolvedUri = p.resolvedUri || resolveUrl(main.uri, p.uri);\n } else {\n // DEPRECATED, this has been added to prevent a breaking change.\n // previously we only ever had a single media group playlist, so\n // we mark the first playlist uri without prepending the index as we used to\n // ideally we would do all of the playlists the same way.\n p.uri = i === 0 ? groupId : id; // don't resolve a placeholder uri to an absolute url, just use\n // the placeholder again\n\n p.resolvedUri = p.uri;\n }\n\n p.id = p.id || id; // add an empty attributes object, all playlists are\n // expected to have this.\n\n p.attributes = p.attributes || {}; // setup ID and URI references (URI for backwards compatibility)\n\n main.playlists[p.id] = p;\n main.playlists[p.uri] = p;\n });\n });\n setupMediaPlaylists(main);\n resolveMediaGroupUris(main);\n};\n\nclass DateRangesStorage {\n constructor() {\n this.offset_ = null;\n this.pendingDateRanges_ = new Map();\n this.processedDateRanges_ = new Map();\n }\n\n setOffset(segments = []) {\n // already set\n if (this.offset_ !== null) {\n return;\n } // no segment to process\n\n\n if (!segments.length) {\n return;\n }\n\n const [firstSegment] = segments; // no program date time\n\n if (firstSegment.programDateTime === undefined) {\n return;\n } // Set offset as ProgramDateTime for the very first segment of the very first playlist load:\n\n\n this.offset_ = firstSegment.programDateTime / 1000;\n }\n\n setPendingDateRanges(dateRanges = []) {\n if (!dateRanges.length) {\n return;\n }\n\n const [dateRange] = dateRanges;\n const startTime = dateRange.startDate.getTime();\n this.trimProcessedDateRanges_(startTime);\n this.pendingDateRanges_ = dateRanges.reduce((map, pendingDateRange) => {\n map.set(pendingDateRange.id, pendingDateRange);\n return map;\n }, new Map());\n }\n\n processDateRange(dateRange) {\n this.pendingDateRanges_.delete(dateRange.id);\n this.processedDateRanges_.set(dateRange.id, dateRange);\n }\n\n getDateRangesToProcess() {\n if (this.offset_ === null) {\n return [];\n }\n\n const dateRangeClasses = {};\n const dateRangesToProcess = [];\n this.pendingDateRanges_.forEach((dateRange, id) => {\n if (this.processedDateRanges_.has(id)) {\n return;\n }\n\n dateRange.startTime = dateRange.startDate.getTime() / 1000 - this.offset_;\n\n dateRange.processDateRange = () => this.processDateRange(dateRange);\n\n dateRangesToProcess.push(dateRange);\n\n if (!dateRange.class) {\n return;\n }\n\n if (dateRangeClasses[dateRange.class]) {\n const length = dateRangeClasses[dateRange.class].push(dateRange);\n dateRange.classListIndex = length - 1;\n } else {\n dateRangeClasses[dateRange.class] = [dateRange];\n dateRange.classListIndex = 0;\n }\n });\n\n for (const dateRange of dateRangesToProcess) {\n const classList = dateRangeClasses[dateRange.class] || [];\n\n if (dateRange.endDate) {\n dateRange.endTime = dateRange.endDate.getTime() / 1000 - this.offset_;\n } else if (dateRange.endOnNext && classList[dateRange.classListIndex + 1]) {\n dateRange.endTime = classList[dateRange.classListIndex + 1].startTime;\n } else if (dateRange.duration) {\n dateRange.endTime = dateRange.startTime + dateRange.duration;\n } else if (dateRange.plannedDuration) {\n dateRange.endTime = dateRange.startTime + dateRange.plannedDuration;\n } else {\n dateRange.endTime = dateRange.startTime;\n }\n }\n\n return dateRangesToProcess;\n }\n\n trimProcessedDateRanges_(startTime) {\n const copy = new Map(this.processedDateRanges_);\n copy.forEach((dateRange, id) => {\n if (dateRange.startDate.getTime() < startTime) {\n this.processedDateRanges_.delete(id);\n }\n });\n }\n\n}\n\nconst QUOTA_EXCEEDED_ERR = 22;\nconst getStreamingNetworkErrorMetadata = ({\n requestType,\n request,\n error,\n parseFailure\n}) => {\n const isBadStatus = request.status < 200 || request.status > 299;\n const isFailure = request.status >= 400 && request.status <= 499;\n const errorMetadata = {\n uri: request.uri,\n requestType\n };\n const isBadStatusOrParseFailure = isBadStatus && !isFailure || parseFailure;\n\n if (error && isFailure) {\n // copy original error and add to the metadata.\n errorMetadata.error = _extends({}, error);\n errorMetadata.errorType = videojs.Error.NetworkRequestFailed;\n } else if (request.aborted) {\n errorMetadata.errorType = videojs.Error.NetworkRequestAborted;\n } else if (request.timedout) {\n errorMetadata.erroType = videojs.Error.NetworkRequestTimeout;\n } else if (isBadStatusOrParseFailure) {\n const errorType = parseFailure ? videojs.Error.NetworkBodyParserFailed : videojs.Error.NetworkBadStatus;\n errorMetadata.errorType = errorType;\n errorMetadata.status = request.status;\n errorMetadata.headers = request.headers;\n }\n\n return errorMetadata;\n};\n\nconst {\n EventTarget: EventTarget$1\n} = videojs;\n\nconst addLLHLSQueryDirectives = (uri, media) => {\n if (media.endList || !media.serverControl) {\n return uri;\n }\n\n const parameters = {};\n\n if (media.serverControl.canBlockReload) {\n const {\n preloadSegment\n } = media; // next msn is a zero based value, length is not.\n\n let nextMSN = media.mediaSequence + media.segments.length; // If preload segment has parts then it is likely\n // that we are going to request a part of that preload segment.\n // the logic below is used to determine that.\n\n if (preloadSegment) {\n const parts = preloadSegment.parts || []; // _HLS_part is a zero based index\n\n const nextPart = getKnownPartCount(media) - 1; // if nextPart is > -1 and not equal to just the\n // length of parts, then we know we had part preload hints\n // and we need to add the _HLS_part= query\n\n if (nextPart > -1 && nextPart !== parts.length - 1) {\n // add existing parts to our preload hints\n // eslint-disable-next-line\n parameters._HLS_part = nextPart;\n } // this if statement makes sure that we request the msn\n // of the preload segment if:\n // 1. the preload segment had parts (and was not yet a full segment)\n // but was added to our segments array\n // 2. the preload segment had preload hints for parts that are not in\n // the manifest yet.\n // in all other cases we want the segment after the preload segment\n // which will be given by using media.segments.length because it is 1 based\n // rather than 0 based.\n\n\n if (nextPart > -1 || parts.length) {\n nextMSN--;\n }\n } // add _HLS_msn= in front of any _HLS_part query\n // eslint-disable-next-line\n\n\n parameters._HLS_msn = nextMSN;\n }\n\n if (media.serverControl && media.serverControl.canSkipUntil) {\n // add _HLS_skip= infront of all other queries.\n // eslint-disable-next-line\n parameters._HLS_skip = media.serverControl.canSkipDateranges ? 'v2' : 'YES';\n }\n\n if (Object.keys(parameters).length) {\n const parsedUri = new window$1.URL(uri);\n ['_HLS_skip', '_HLS_msn', '_HLS_part'].forEach(function (name) {\n if (!parameters.hasOwnProperty(name)) {\n return;\n }\n\n parsedUri.searchParams.set(name, parameters[name]);\n });\n uri = parsedUri.toString();\n }\n\n return uri;\n};\n/**\n * Returns a new segment object with properties and\n * the parts array merged.\n *\n * @param {Object} a the old segment\n * @param {Object} b the new segment\n *\n * @return {Object} the merged segment\n */\n\n\nconst updateSegment = (a, b) => {\n if (!a) {\n return b;\n }\n\n const result = merge(a, b); // if only the old segment has preload hints\n // and the new one does not, remove preload hints.\n\n if (a.preloadHints && !b.preloadHints) {\n delete result.preloadHints;\n } // if only the old segment has parts\n // then the parts are no longer valid\n\n\n if (a.parts && !b.parts) {\n delete result.parts; // if both segments have parts\n // copy part propeties from the old segment\n // to the new one.\n } else if (a.parts && b.parts) {\n for (let i = 0; i < b.parts.length; i++) {\n if (a.parts && a.parts[i]) {\n result.parts[i] = merge(a.parts[i], b.parts[i]);\n }\n }\n } // set skipped to false for segments that have\n // have had information merged from the old segment.\n\n\n if (!a.skipped && b.skipped) {\n result.skipped = false;\n } // set preload to false for segments that have\n // had information added in the new segment.\n\n\n if (a.preload && !b.preload) {\n result.preload = false;\n }\n\n return result;\n};\n/**\n * Returns a new array of segments that is the result of merging\n * properties from an older list of segments onto an updated\n * list. No properties on the updated playlist will be ovewritten.\n *\n * @param {Array} original the outdated list of segments\n * @param {Array} update the updated list of segments\n * @param {number=} offset the index of the first update\n * segment in the original segment list. For non-live playlists,\n * this should always be zero and does not need to be\n * specified. For live playlists, it should be the difference\n * between the media sequence numbers in the original and updated\n * playlists.\n * @return {Array} a list of merged segment objects\n */\n\nconst updateSegments = (original, update, offset) => {\n const oldSegments = original.slice();\n const newSegments = update.slice();\n offset = offset || 0;\n const result = [];\n let currentMap;\n\n for (let newIndex = 0; newIndex < newSegments.length; newIndex++) {\n const oldSegment = oldSegments[newIndex + offset];\n const newSegment = newSegments[newIndex];\n\n if (oldSegment) {\n currentMap = oldSegment.map || currentMap;\n result.push(updateSegment(oldSegment, newSegment));\n } else {\n // carry over map to new segment if it is missing\n if (currentMap && !newSegment.map) {\n newSegment.map = currentMap;\n }\n\n result.push(newSegment);\n }\n }\n\n return result;\n};\nconst resolveSegmentUris = (segment, baseUri) => {\n // preloadSegment will not have a uri at all\n // as the segment isn't actually in the manifest yet, only parts\n if (!segment.resolvedUri && segment.uri) {\n segment.resolvedUri = resolveUrl(baseUri, segment.uri);\n }\n\n if (segment.key && !segment.key.resolvedUri) {\n segment.key.resolvedUri = resolveUrl(baseUri, segment.key.uri);\n }\n\n if (segment.map && !segment.map.resolvedUri) {\n segment.map.resolvedUri = resolveUrl(baseUri, segment.map.uri);\n }\n\n if (segment.map && segment.map.key && !segment.map.key.resolvedUri) {\n segment.map.key.resolvedUri = resolveUrl(baseUri, segment.map.key.uri);\n }\n\n if (segment.parts && segment.parts.length) {\n segment.parts.forEach(p => {\n if (p.resolvedUri) {\n return;\n }\n\n p.resolvedUri = resolveUrl(baseUri, p.uri);\n });\n }\n\n if (segment.preloadHints && segment.preloadHints.length) {\n segment.preloadHints.forEach(p => {\n if (p.resolvedUri) {\n return;\n }\n\n p.resolvedUri = resolveUrl(baseUri, p.uri);\n });\n }\n};\n\nconst getAllSegments = function (media) {\n const segments = media.segments || [];\n const preloadSegment = media.preloadSegment; // a preloadSegment with only preloadHints is not currently\n // a usable segment, only include a preloadSegment that has\n // parts.\n\n if (preloadSegment && preloadSegment.parts && preloadSegment.parts.length) {\n // if preloadHints has a MAP that means that the\n // init segment is going to change. We cannot use any of the parts\n // from this preload segment.\n if (preloadSegment.preloadHints) {\n for (let i = 0; i < preloadSegment.preloadHints.length; i++) {\n if (preloadSegment.preloadHints[i].type === 'MAP') {\n return segments;\n }\n }\n } // set the duration for our preload segment to target duration.\n\n\n preloadSegment.duration = media.targetDuration;\n preloadSegment.preload = true;\n segments.push(preloadSegment);\n }\n\n return segments;\n}; // consider the playlist unchanged if the playlist object is the same or\n// the number of segments is equal, the media sequence number is unchanged,\n// and this playlist hasn't become the end of the playlist\n\n\nconst isPlaylistUnchanged = (a, b) => a === b || a.segments && b.segments && a.segments.length === b.segments.length && a.endList === b.endList && a.mediaSequence === b.mediaSequence && a.preloadSegment === b.preloadSegment;\n/**\n * Returns a new main playlist that is the result of merging an\n * updated media playlist into the original version. If the\n * updated media playlist does not match any of the playlist\n * entries in the original main playlist, null is returned.\n *\n * @param {Object} main a parsed main M3U8 object\n * @param {Object} media a parsed media M3U8 object\n * @return {Object} a new object that represents the original\n * main playlist with the updated media playlist merged in, or\n * null if the merge produced no change.\n */\n\nconst updateMain$1 = (main, newMedia, unchangedCheck = isPlaylistUnchanged) => {\n const result = merge(main, {});\n const oldMedia = result.playlists[newMedia.id];\n\n if (!oldMedia) {\n return null;\n }\n\n if (unchangedCheck(oldMedia, newMedia)) {\n return null;\n }\n\n newMedia.segments = getAllSegments(newMedia);\n const mergedPlaylist = merge(oldMedia, newMedia); // always use the new media's preload segment\n\n if (mergedPlaylist.preloadSegment && !newMedia.preloadSegment) {\n delete mergedPlaylist.preloadSegment;\n } // if the update could overlap existing segment information, merge the two segment lists\n\n\n if (oldMedia.segments) {\n if (newMedia.skip) {\n newMedia.segments = newMedia.segments || []; // add back in objects for skipped segments, so that we merge\n // old properties into the new segments\n\n for (let i = 0; i < newMedia.skip.skippedSegments; i++) {\n newMedia.segments.unshift({\n skipped: true\n });\n }\n }\n\n mergedPlaylist.segments = updateSegments(oldMedia.segments, newMedia.segments, newMedia.mediaSequence - oldMedia.mediaSequence);\n } // resolve any segment URIs to prevent us from having to do it later\n\n\n mergedPlaylist.segments.forEach(segment => {\n resolveSegmentUris(segment, mergedPlaylist.resolvedUri);\n }); // TODO Right now in the playlists array there are two references to each playlist, one\n // that is referenced by index, and one by URI. The index reference may no longer be\n // necessary.\n\n for (let i = 0; i < result.playlists.length; i++) {\n if (result.playlists[i].id === newMedia.id) {\n result.playlists[i] = mergedPlaylist;\n }\n }\n\n result.playlists[newMedia.id] = mergedPlaylist; // URI reference added for backwards compatibility\n\n result.playlists[newMedia.uri] = mergedPlaylist; // update media group playlist references.\n\n forEachMediaGroup(main, (properties, mediaType, groupKey, labelKey) => {\n if (!properties.playlists) {\n return;\n }\n\n for (let i = 0; i < properties.playlists.length; i++) {\n if (newMedia.id === properties.playlists[i].id) {\n properties.playlists[i] = mergedPlaylist;\n }\n }\n });\n return result;\n};\n/**\n * Calculates the time to wait before refreshing a live playlist\n *\n * @param {Object} media\n * The current media\n * @param {boolean} update\n * True if there were any updates from the last refresh, false otherwise\n * @return {number}\n * The time in ms to wait before refreshing the live playlist\n */\n\nconst refreshDelay = (media, update) => {\n const segments = media.segments || [];\n const lastSegment = segments[segments.length - 1];\n const lastPart = lastSegment && lastSegment.parts && lastSegment.parts[lastSegment.parts.length - 1];\n const lastDuration = lastPart && lastPart.duration || lastSegment && lastSegment.duration;\n\n if (update && lastDuration) {\n return lastDuration * 1000;\n } // if the playlist is unchanged since the last reload or last segment duration\n // cannot be determined, try again after half the target duration\n\n\n return (media.partTargetDuration || media.targetDuration || 10) * 500;\n};\n\nconst playlistMetadataPayload = (playlists, type, isLive) => {\n if (!playlists) {\n return;\n }\n\n const renditions = [];\n playlists.forEach(playlist => {\n // we need attributes to populate rendition data.\n if (!playlist.attributes) {\n return;\n }\n\n const {\n BANDWIDTH,\n RESOLUTION,\n CODECS\n } = playlist.attributes;\n renditions.push({\n id: playlist.id,\n bandwidth: BANDWIDTH,\n resolution: RESOLUTION,\n codecs: CODECS\n });\n });\n return {\n type,\n isLive,\n renditions\n };\n};\n/**\n * Load a playlist from a remote location\n *\n * @class PlaylistLoader\n * @extends Stream\n * @param {string|Object} src url or object of manifest\n * @param {boolean} withCredentials the withCredentials xhr option\n * @class\n */\n\n\nclass PlaylistLoader extends EventTarget$1 {\n constructor(src, vhs, options = {}) {\n super();\n\n if (!src) {\n throw new Error('A non-empty playlist URL or object is required');\n }\n\n this.logger_ = logger('PlaylistLoader');\n const {\n withCredentials = false\n } = options;\n this.src = src;\n this.vhs_ = vhs;\n this.withCredentials = withCredentials;\n this.addDateRangesToTextTrack_ = options.addDateRangesToTextTrack;\n const vhsOptions = vhs.options_;\n this.customTagParsers = vhsOptions && vhsOptions.customTagParsers || [];\n this.customTagMappers = vhsOptions && vhsOptions.customTagMappers || [];\n this.llhls = vhsOptions && vhsOptions.llhls;\n this.dateRangesStorage_ = new DateRangesStorage(); // initialize the loader state\n\n this.state = 'HAVE_NOTHING'; // live playlist staleness timeout\n\n this.handleMediaupdatetimeout_ = this.handleMediaupdatetimeout_.bind(this);\n this.on('mediaupdatetimeout', this.handleMediaupdatetimeout_);\n this.on('loadedplaylist', this.handleLoadedPlaylist_.bind(this));\n }\n\n handleLoadedPlaylist_() {\n const mediaPlaylist = this.media();\n\n if (!mediaPlaylist) {\n return;\n }\n\n this.dateRangesStorage_.setOffset(mediaPlaylist.segments);\n this.dateRangesStorage_.setPendingDateRanges(mediaPlaylist.dateRanges);\n const availableDateRanges = this.dateRangesStorage_.getDateRangesToProcess();\n\n if (!availableDateRanges.length || !this.addDateRangesToTextTrack_) {\n return;\n }\n\n this.addDateRangesToTextTrack_(availableDateRanges);\n }\n\n handleMediaupdatetimeout_() {\n if (this.state !== 'HAVE_METADATA') {\n // only refresh the media playlist if no other activity is going on\n return;\n }\n\n const media = this.media();\n let uri = resolveUrl(this.main.uri, media.uri);\n\n if (this.llhls) {\n uri = addLLHLSQueryDirectives(uri, media);\n }\n\n this.state = 'HAVE_CURRENT_METADATA';\n this.request = this.vhs_.xhr({\n uri,\n withCredentials: this.withCredentials,\n requestType: 'hls-playlist'\n }, (error, req) => {\n // disposed\n if (!this.request) {\n return;\n }\n\n if (error) {\n return this.playlistRequestError(this.request, this.media(), 'HAVE_METADATA');\n }\n\n this.haveMetadata({\n playlistString: this.request.responseText,\n url: this.media().uri,\n id: this.media().id\n });\n });\n }\n\n playlistRequestError(xhr, playlist, startingState) {\n const {\n uri,\n id\n } = playlist; // any in-flight request is now finished\n\n this.request = null;\n\n if (startingState) {\n this.state = startingState;\n }\n\n this.error = {\n playlist: this.main.playlists[id],\n status: xhr.status,\n message: `HLS playlist request error at URL: ${uri}.`,\n responseText: xhr.responseText,\n code: xhr.status >= 500 ? 4 : 2,\n metadata: getStreamingNetworkErrorMetadata({\n requestType: xhr.requestType,\n request: xhr,\n error: xhr.error\n })\n };\n this.trigger('error');\n }\n\n parseManifest_({\n url,\n manifestString\n }) {\n try {\n return parseManifest({\n onwarn: ({\n message\n }) => this.logger_(`m3u8-parser warn for ${url}: ${message}`),\n oninfo: ({\n message\n }) => this.logger_(`m3u8-parser info for ${url}: ${message}`),\n manifestString,\n customTagParsers: this.customTagParsers,\n customTagMappers: this.customTagMappers,\n llhls: this.llhls\n });\n } catch (error) {\n this.error = error;\n this.error.metadata = {\n errorType: videojs.Error.StreamingHlsPlaylistParserError,\n error\n };\n }\n }\n /**\n * Update the playlist loader's state in response to a new or updated playlist.\n *\n * @param {string} [playlistString]\n * Playlist string (if playlistObject is not provided)\n * @param {Object} [playlistObject]\n * Playlist object (if playlistString is not provided)\n * @param {string} url\n * URL of playlist\n * @param {string} id\n * ID to use for playlist\n */\n\n\n haveMetadata({\n playlistString,\n playlistObject,\n url,\n id\n }) {\n // any in-flight request is now finished\n this.request = null;\n this.state = 'HAVE_METADATA';\n const metadata = {\n playlistInfo: {\n type: 'media',\n uri: url\n }\n };\n this.trigger({\n type: 'playlistparsestart',\n metadata\n });\n const playlist = playlistObject || this.parseManifest_({\n url,\n manifestString: playlistString\n });\n playlist.lastRequest = Date.now();\n setupMediaPlaylist({\n playlist,\n uri: url,\n id\n }); // merge this playlist into the main manifest\n\n const update = updateMain$1(this.main, playlist);\n this.targetDuration = playlist.partTargetDuration || playlist.targetDuration;\n this.pendingMedia_ = null;\n\n if (update) {\n this.main = update;\n this.media_ = this.main.playlists[id];\n } else {\n this.trigger('playlistunchanged');\n }\n\n this.updateMediaUpdateTimeout_(refreshDelay(this.media(), !!update));\n metadata.parsedPlaylist = playlistMetadataPayload(this.main.playlists, metadata.playlistInfo.type, !this.media_.endList);\n this.trigger({\n type: 'playlistparsecomplete',\n metadata\n });\n this.trigger('loadedplaylist');\n }\n /**\n * Abort any outstanding work and clean up.\n */\n\n\n dispose() {\n this.trigger('dispose');\n this.stopRequest();\n window$1.clearTimeout(this.mediaUpdateTimeout);\n window$1.clearTimeout(this.finalRenditionTimeout);\n this.dateRangesStorage_ = new DateRangesStorage();\n this.off();\n }\n\n stopRequest() {\n if (this.request) {\n const oldRequest = this.request;\n this.request = null;\n oldRequest.onreadystatechange = null;\n oldRequest.abort();\n }\n }\n /**\n * When called without any arguments, returns the currently\n * active media playlist. When called with a single argument,\n * triggers the playlist loader to asynchronously switch to the\n * specified media playlist. Calling this method while the\n * loader is in the HAVE_NOTHING causes an error to be emitted\n * but otherwise has no effect.\n *\n * @param {Object=} playlist the parsed media playlist\n * object to switch to\n * @param {boolean=} shouldDelay whether we should delay the request by half target duration\n *\n * @return {Playlist} the current loaded media\n */\n\n\n media(playlist, shouldDelay) {\n // getter\n if (!playlist) {\n return this.media_;\n } // setter\n\n\n if (this.state === 'HAVE_NOTHING') {\n throw new Error('Cannot switch media playlist from ' + this.state);\n } // find the playlist object if the target playlist has been\n // specified by URI\n\n\n if (typeof playlist === 'string') {\n if (!this.main.playlists[playlist]) {\n throw new Error('Unknown playlist URI: ' + playlist);\n }\n\n playlist = this.main.playlists[playlist];\n }\n\n window$1.clearTimeout(this.finalRenditionTimeout);\n\n if (shouldDelay) {\n const delay = (playlist.partTargetDuration || playlist.targetDuration) / 2 * 1000 || 5 * 1000;\n this.finalRenditionTimeout = window$1.setTimeout(this.media.bind(this, playlist, false), delay);\n return;\n }\n\n const startingState = this.state;\n const mediaChange = !this.media_ || playlist.id !== this.media_.id;\n const mainPlaylistRef = this.main.playlists[playlist.id]; // switch to fully loaded playlists immediately\n\n if (mainPlaylistRef && mainPlaylistRef.endList || // handle the case of a playlist object (e.g., if using vhs-json with a resolved\n // media playlist or, for the case of demuxed audio, a resolved audio media group)\n playlist.endList && playlist.segments.length) {\n // abort outstanding playlist requests\n if (this.request) {\n this.request.onreadystatechange = null;\n this.request.abort();\n this.request = null;\n }\n\n this.state = 'HAVE_METADATA';\n this.media_ = playlist; // trigger media change if the active media has been updated\n\n if (mediaChange) {\n this.trigger('mediachanging');\n\n if (startingState === 'HAVE_MAIN_MANIFEST') {\n // The initial playlist was a main manifest, and the first media selected was\n // also provided (in the form of a resolved playlist object) as part of the\n // source object (rather than just a URL). Therefore, since the media playlist\n // doesn't need to be requested, loadedmetadata won't trigger as part of the\n // normal flow, and needs an explicit trigger here.\n this.trigger('loadedmetadata');\n } else {\n this.trigger('mediachange');\n }\n }\n\n return;\n } // We update/set the timeout here so that live playlists\n // that are not a media change will \"start\" the loader as expected.\n // We expect that this function will start the media update timeout\n // cycle again. This also prevents a playlist switch failure from\n // causing us to stall during live.\n\n\n this.updateMediaUpdateTimeout_(refreshDelay(playlist, true)); // switching to the active playlist is a no-op\n\n if (!mediaChange) {\n return;\n }\n\n this.state = 'SWITCHING_MEDIA'; // there is already an outstanding playlist request\n\n if (this.request) {\n if (playlist.resolvedUri === this.request.url) {\n // requesting to switch to the same playlist multiple times\n // has no effect after the first\n return;\n }\n\n this.request.onreadystatechange = null;\n this.request.abort();\n this.request = null;\n } // request the new playlist\n\n\n if (this.media_) {\n this.trigger('mediachanging');\n }\n\n this.pendingMedia_ = playlist;\n const metadata = {\n playlistInfo: {\n type: 'media',\n uri: playlist.uri\n }\n };\n this.trigger({\n type: 'playlistrequeststart',\n metadata\n });\n this.request = this.vhs_.xhr({\n uri: playlist.resolvedUri,\n withCredentials: this.withCredentials,\n requestType: 'hls-playlist'\n }, (error, req) => {\n // disposed\n if (!this.request) {\n return;\n }\n\n playlist.lastRequest = Date.now();\n playlist.resolvedUri = resolveManifestRedirect(playlist.resolvedUri, req);\n\n if (error) {\n return this.playlistRequestError(this.request, playlist, startingState);\n }\n\n this.trigger({\n type: 'playlistrequestcomplete',\n metadata\n });\n this.haveMetadata({\n playlistString: req.responseText,\n url: playlist.uri,\n id: playlist.id\n }); // fire loadedmetadata the first time a media playlist is loaded\n\n if (startingState === 'HAVE_MAIN_MANIFEST') {\n this.trigger('loadedmetadata');\n } else {\n this.trigger('mediachange');\n }\n });\n }\n /**\n * pause loading of the playlist\n */\n\n\n pause() {\n if (this.mediaUpdateTimeout) {\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n }\n\n this.stopRequest();\n\n if (this.state === 'HAVE_NOTHING') {\n // If we pause the loader before any data has been retrieved, its as if we never\n // started, so reset to an unstarted state.\n this.started = false;\n } // Need to restore state now that no activity is happening\n\n\n if (this.state === 'SWITCHING_MEDIA') {\n // if the loader was in the process of switching media, it should either return to\n // HAVE_MAIN_MANIFEST or HAVE_METADATA depending on if the loader has loaded a media\n // playlist yet. This is determined by the existence of loader.media_\n if (this.media_) {\n this.state = 'HAVE_METADATA';\n } else {\n this.state = 'HAVE_MAIN_MANIFEST';\n }\n } else if (this.state === 'HAVE_CURRENT_METADATA') {\n this.state = 'HAVE_METADATA';\n }\n }\n /**\n * start loading of the playlist\n */\n\n\n load(shouldDelay) {\n if (this.mediaUpdateTimeout) {\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n }\n\n const media = this.media();\n\n if (shouldDelay) {\n const delay = media ? (media.partTargetDuration || media.targetDuration) / 2 * 1000 : 5 * 1000;\n this.mediaUpdateTimeout = window$1.setTimeout(() => {\n this.mediaUpdateTimeout = null;\n this.load();\n }, delay);\n return;\n }\n\n if (!this.started) {\n this.start();\n return;\n }\n\n if (media && !media.endList) {\n this.trigger('mediaupdatetimeout');\n } else {\n this.trigger('loadedplaylist');\n }\n }\n\n updateMediaUpdateTimeout_(delay) {\n if (this.mediaUpdateTimeout) {\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n } // we only have use mediaupdatetimeout for live playlists.\n\n\n if (!this.media() || this.media().endList) {\n return;\n }\n\n this.mediaUpdateTimeout = window$1.setTimeout(() => {\n this.mediaUpdateTimeout = null;\n this.trigger('mediaupdatetimeout');\n this.updateMediaUpdateTimeout_(delay);\n }, delay);\n }\n /**\n * start loading of the playlist\n */\n\n\n start() {\n this.started = true;\n\n if (typeof this.src === 'object') {\n // in the case of an entirely constructed manifest object (meaning there's no actual\n // manifest on a server), default the uri to the page's href\n if (!this.src.uri) {\n this.src.uri = window$1.location.href;\n } // resolvedUri is added on internally after the initial request. Since there's no\n // request for pre-resolved manifests, add on resolvedUri here.\n\n\n this.src.resolvedUri = this.src.uri; // Since a manifest object was passed in as the source (instead of a URL), the first\n // request can be skipped (since the top level of the manifest, at a minimum, is\n // already available as a parsed manifest object). However, if the manifest object\n // represents a main playlist, some media playlists may need to be resolved before\n // the starting segment list is available. Therefore, go directly to setup of the\n // initial playlist, and let the normal flow continue from there.\n //\n // Note that the call to setup is asynchronous, as other sections of VHS may assume\n // that the first request is asynchronous.\n\n setTimeout(() => {\n this.setupInitialPlaylist(this.src);\n }, 0);\n return;\n }\n\n const metadata = {\n playlistInfo: {\n type: 'multivariant',\n uri: this.src\n }\n };\n this.trigger({\n type: 'playlistrequeststart',\n metadata\n }); // request the specified URL\n\n this.request = this.vhs_.xhr({\n uri: this.src,\n withCredentials: this.withCredentials,\n requestType: 'hls-playlist'\n }, (error, req) => {\n // disposed\n if (!this.request) {\n return;\n } // clear the loader's request reference\n\n\n this.request = null;\n\n if (error) {\n this.error = {\n status: req.status,\n message: `HLS playlist request error at URL: ${this.src}.`,\n responseText: req.responseText,\n // MEDIA_ERR_NETWORK\n code: 2,\n metadata: getStreamingNetworkErrorMetadata({\n requestType: req.requestType,\n request: req,\n error\n })\n };\n\n if (this.state === 'HAVE_NOTHING') {\n this.started = false;\n }\n\n return this.trigger('error');\n }\n\n this.trigger({\n type: 'playlistrequestcomplete',\n metadata\n });\n this.src = resolveManifestRedirect(this.src, req);\n this.trigger({\n type: 'playlistparsestart',\n metadata\n });\n const manifest = this.parseManifest_({\n manifestString: req.responseText,\n url: this.src\n }); // we haven't loaded any variant playlists here so we default to false for isLive.\n\n metadata.parsedPlaylist = playlistMetadataPayload(manifest.playlists, metadata.playlistInfo.type, false);\n this.trigger({\n type: 'playlistparsecomplete',\n metadata\n });\n this.setupInitialPlaylist(manifest);\n });\n }\n\n srcUri() {\n return typeof this.src === 'string' ? this.src : this.src.uri;\n }\n /**\n * Given a manifest object that's either a main or media playlist, trigger the proper\n * events and set the state of the playlist loader.\n *\n * If the manifest object represents a main playlist, `loadedplaylist` will be\n * triggered to allow listeners to select a playlist. If none is selected, the loader\n * will default to the first one in the playlists array.\n *\n * If the manifest object represents a media playlist, `loadedplaylist` will be\n * triggered followed by `loadedmetadata`, as the only available playlist is loaded.\n *\n * In the case of a media playlist, a main playlist object wrapper with one playlist\n * will be created so that all logic can handle playlists in the same fashion (as an\n * assumed manifest object schema).\n *\n * @param {Object} manifest\n * The parsed manifest object\n */\n\n\n setupInitialPlaylist(manifest) {\n this.state = 'HAVE_MAIN_MANIFEST';\n\n if (manifest.playlists) {\n this.main = manifest;\n addPropertiesToMain(this.main, this.srcUri()); // If the initial main playlist has playlists wtih segments already resolved,\n // then resolve URIs in advance, as they are usually done after a playlist request,\n // which may not happen if the playlist is resolved.\n\n manifest.playlists.forEach(playlist => {\n playlist.segments = getAllSegments(playlist);\n playlist.segments.forEach(segment => {\n resolveSegmentUris(segment, playlist.resolvedUri);\n });\n });\n this.trigger('loadedplaylist');\n\n if (!this.request) {\n // no media playlist was specifically selected so start\n // from the first listed one\n this.media(this.main.playlists[0]);\n }\n\n return;\n } // In order to support media playlists passed in as vhs-json, the case where the uri\n // is not provided as part of the manifest should be considered, and an appropriate\n // default used.\n\n\n const uri = this.srcUri() || window$1.location.href;\n this.main = mainForMedia(manifest, uri);\n this.haveMetadata({\n playlistObject: manifest,\n url: uri,\n id: this.main.playlists[0].id\n });\n this.trigger('loadedmetadata');\n }\n /**\n * Updates or deletes a preexisting pathway clone.\n * Ensures that all playlists related to the old pathway clone are\n * either updated or deleted.\n *\n * @param {Object} clone On update, the pathway clone object for the newly updated pathway clone.\n * On delete, the old pathway clone object to be deleted.\n * @param {boolean} isUpdate True if the pathway is to be updated,\n * false if it is meant to be deleted.\n */\n\n\n updateOrDeleteClone(clone, isUpdate) {\n const main = this.main;\n const pathway = clone.ID;\n let i = main.playlists.length; // Iterate backwards through the playlist so we can remove playlists if necessary.\n\n while (i--) {\n const p = main.playlists[i];\n\n if (p.attributes['PATHWAY-ID'] === pathway) {\n const oldPlaylistUri = p.resolvedUri;\n const oldPlaylistId = p.id; // update the indexed playlist and add new playlists by ID and URI\n\n if (isUpdate) {\n const newPlaylistUri = this.createCloneURI_(p.resolvedUri, clone);\n const newPlaylistId = createPlaylistID(pathway, newPlaylistUri);\n const attributes = this.createCloneAttributes_(pathway, p.attributes);\n const updatedPlaylist = this.createClonePlaylist_(p, newPlaylistId, clone, attributes);\n main.playlists[i] = updatedPlaylist;\n main.playlists[newPlaylistId] = updatedPlaylist;\n main.playlists[newPlaylistUri] = updatedPlaylist;\n } else {\n // Remove the indexed playlist.\n main.playlists.splice(i, 1);\n } // Remove playlists by the old ID and URI.\n\n\n delete main.playlists[oldPlaylistId];\n delete main.playlists[oldPlaylistUri];\n }\n }\n\n this.updateOrDeleteCloneMedia(clone, isUpdate);\n }\n /**\n * Updates or deletes media data based on the pathway clone object.\n * Due to the complexity of the media groups and playlists, in all cases\n * we remove all of the old media groups and playlists.\n * On updates, we then create new media groups and playlists based on the\n * new pathway clone object.\n *\n * @param {Object} clone The pathway clone object for the newly updated pathway clone.\n * @param {boolean} isUpdate True if the pathway is to be updated,\n * false if it is meant to be deleted.\n */\n\n\n updateOrDeleteCloneMedia(clone, isUpdate) {\n const main = this.main;\n const id = clone.ID;\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(mediaType => {\n if (!main.mediaGroups[mediaType] || !main.mediaGroups[mediaType][id]) {\n return;\n }\n\n for (const groupKey in main.mediaGroups[mediaType]) {\n // Remove all media playlists for the media group for this pathway clone.\n if (groupKey === id) {\n for (const labelKey in main.mediaGroups[mediaType][groupKey]) {\n const oldMedia = main.mediaGroups[mediaType][groupKey][labelKey];\n oldMedia.playlists.forEach((p, i) => {\n const oldMediaPlaylist = main.playlists[p.id];\n const oldPlaylistId = oldMediaPlaylist.id;\n const oldPlaylistUri = oldMediaPlaylist.resolvedUri;\n delete main.playlists[oldPlaylistId];\n delete main.playlists[oldPlaylistUri];\n });\n } // Delete the old media group.\n\n\n delete main.mediaGroups[mediaType][groupKey];\n }\n }\n }); // Create the new media groups and playlists if there is an update.\n\n if (isUpdate) {\n this.createClonedMediaGroups_(clone);\n }\n }\n /**\n * Given a pathway clone object, clones all necessary playlists.\n *\n * @param {Object} clone The pathway clone object.\n * @param {Object} basePlaylist The original playlist to clone from.\n */\n\n\n addClonePathway(clone, basePlaylist = {}) {\n const main = this.main;\n const index = main.playlists.length;\n const uri = this.createCloneURI_(basePlaylist.resolvedUri, clone);\n const playlistId = createPlaylistID(clone.ID, uri);\n const attributes = this.createCloneAttributes_(clone.ID, basePlaylist.attributes);\n const playlist = this.createClonePlaylist_(basePlaylist, playlistId, clone, attributes);\n main.playlists[index] = playlist; // add playlist by ID and URI\n\n main.playlists[playlistId] = playlist;\n main.playlists[uri] = playlist;\n this.createClonedMediaGroups_(clone);\n }\n /**\n * Given a pathway clone object we create clones of all media.\n * In this function, all necessary information and updated playlists\n * are added to the `mediaGroup` object.\n * Playlists are also added to the `playlists` array so the media groups\n * will be properly linked.\n *\n * @param {Object} clone The pathway clone object.\n */\n\n\n createClonedMediaGroups_(clone) {\n const id = clone.ID;\n const baseID = clone['BASE-ID'];\n const main = this.main;\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(mediaType => {\n // If the media type doesn't exist, or there is already a clone, skip\n // to the next media type.\n if (!main.mediaGroups[mediaType] || main.mediaGroups[mediaType][id]) {\n return;\n }\n\n for (const groupKey in main.mediaGroups[mediaType]) {\n if (groupKey === baseID) {\n // Create the group.\n main.mediaGroups[mediaType][id] = {};\n } else {\n // There is no need to iterate over label keys in this case.\n continue;\n }\n\n for (const labelKey in main.mediaGroups[mediaType][groupKey]) {\n const oldMedia = main.mediaGroups[mediaType][groupKey][labelKey];\n main.mediaGroups[mediaType][id][labelKey] = _extends({}, oldMedia);\n const newMedia = main.mediaGroups[mediaType][id][labelKey]; // update URIs on the media\n\n const newUri = this.createCloneURI_(oldMedia.resolvedUri, clone);\n newMedia.resolvedUri = newUri;\n newMedia.uri = newUri; // Reset playlists in the new media group.\n\n newMedia.playlists = []; // Create new playlists in the newly cloned media group.\n\n oldMedia.playlists.forEach((p, i) => {\n const oldMediaPlaylist = main.playlists[p.id];\n const group = groupID(mediaType, id, labelKey);\n const newPlaylistID = createPlaylistID(id, group); // Check to see if it already exists\n\n if (oldMediaPlaylist && !main.playlists[newPlaylistID]) {\n const newMediaPlaylist = this.createClonePlaylist_(oldMediaPlaylist, newPlaylistID, clone);\n const newPlaylistUri = newMediaPlaylist.resolvedUri;\n main.playlists[newPlaylistID] = newMediaPlaylist;\n main.playlists[newPlaylistUri] = newMediaPlaylist;\n }\n\n newMedia.playlists[i] = this.createClonePlaylist_(p, newPlaylistID, clone);\n });\n }\n }\n });\n }\n /**\n * Using the original playlist to be cloned, and the pathway clone object\n * information, we create a new playlist.\n *\n * @param {Object} basePlaylist The original playlist to be cloned from.\n * @param {string} id The desired id of the newly cloned playlist.\n * @param {Object} clone The pathway clone object.\n * @param {Object} attributes An optional object to populate the `attributes` property in the playlist.\n *\n * @return {Object} The combined cloned playlist.\n */\n\n\n createClonePlaylist_(basePlaylist, id, clone, attributes) {\n const uri = this.createCloneURI_(basePlaylist.resolvedUri, clone);\n const newProps = {\n resolvedUri: uri,\n uri,\n id\n }; // Remove all segments from previous playlist in the clone.\n\n if (basePlaylist.segments) {\n newProps.segments = [];\n }\n\n if (attributes) {\n newProps.attributes = attributes;\n }\n\n return merge(basePlaylist, newProps);\n }\n /**\n * Generates an updated URI for a cloned pathway based on the original\n * pathway's URI and the paramaters from the pathway clone object in the\n * content steering server response.\n *\n * @param {string} baseUri URI to be updated in the cloned pathway.\n * @param {Object} clone The pathway clone object.\n *\n * @return {string} The updated URI for the cloned pathway.\n */\n\n\n createCloneURI_(baseURI, clone) {\n const uri = new URL(baseURI);\n uri.hostname = clone['URI-REPLACEMENT'].HOST;\n const params = clone['URI-REPLACEMENT'].PARAMS; // Add params to the cloned URL.\n\n for (const key of Object.keys(params)) {\n uri.searchParams.set(key, params[key]);\n }\n\n return uri.href;\n }\n /**\n * Helper function to create the attributes needed for the new clone.\n * This mainly adds the necessary media attributes.\n *\n * @param {string} id The pathway clone object ID.\n * @param {Object} oldAttributes The old attributes to compare to.\n * @return {Object} The new attributes to add to the playlist.\n */\n\n\n createCloneAttributes_(id, oldAttributes) {\n const attributes = {\n ['PATHWAY-ID']: id\n };\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(mediaType => {\n if (oldAttributes[mediaType]) {\n attributes[mediaType] = id;\n }\n });\n return attributes;\n }\n /**\n * Returns the key ID set from a playlist\n *\n * @param {playlist} playlist to fetch the key ID set from.\n * @return a Set of 32 digit hex strings that represent the unique keyIds for that playlist.\n */\n\n\n getKeyIdSet(playlist) {\n if (playlist.contentProtection) {\n const keyIds = new Set();\n\n for (const keysystem in playlist.contentProtection) {\n const keyId = playlist.contentProtection[keysystem].attributes.keyId;\n\n if (keyId) {\n keyIds.add(keyId.toLowerCase());\n }\n }\n\n return keyIds;\n }\n }\n\n}\n\n/**\n * @file xhr.js\n */\n\nconst callbackWrapper = function (request, error, response, callback) {\n const reqResponse = request.responseType === 'arraybuffer' ? request.response : request.responseText;\n\n if (!error && reqResponse) {\n request.responseTime = Date.now();\n request.roundTripTime = request.responseTime - request.requestTime;\n request.bytesReceived = reqResponse.byteLength || reqResponse.length;\n\n if (!request.bandwidth) {\n request.bandwidth = Math.floor(request.bytesReceived / request.roundTripTime * 8 * 1000);\n }\n }\n\n if (response.headers) {\n request.responseHeaders = response.headers;\n } // videojs.xhr now uses a specific code on the error\n // object to signal that a request has timed out instead\n // of setting a boolean on the request object\n\n\n if (error && error.code === 'ETIMEDOUT') {\n request.timedout = true;\n } // videojs.xhr no longer considers status codes outside of 200 and 0\n // (for file uris) to be errors, but the old XHR did, so emulate that\n // behavior. Status 206 may be used in response to byterange requests.\n\n\n if (!error && !request.aborted && response.statusCode !== 200 && response.statusCode !== 206 && response.statusCode !== 0) {\n error = new Error('XHR Failed with a response of: ' + (request && (reqResponse || request.responseText)));\n }\n\n callback(error, request);\n};\n/**\n * Iterates over the request hooks Set and calls them in order\n *\n * @param {Set} hooks the hook Set to iterate over\n * @param {Object} options the request options to pass to the xhr wrapper\n * @return the callback hook function return value, the modified or new options Object.\n */\n\n\nconst callAllRequestHooks = (requestSet, options) => {\n if (!requestSet || !requestSet.size) {\n return;\n }\n\n let newOptions = options;\n requestSet.forEach(requestCallback => {\n newOptions = requestCallback(newOptions);\n });\n return newOptions;\n};\n/**\n * Iterates over the response hooks Set and calls them in order.\n *\n * @param {Set} hooks the hook Set to iterate over\n * @param {Object} request the xhr request object\n * @param {Object} error the xhr error object\n * @param {Object} response the xhr response object\n */\n\n\nconst callAllResponseHooks = (responseSet, request, error, response) => {\n if (!responseSet || !responseSet.size) {\n return;\n }\n\n responseSet.forEach(responseCallback => {\n responseCallback(request, error, response);\n });\n};\n\nconst xhrFactory = function () {\n const xhr = function XhrFunction(options, callback) {\n // Add a default timeout\n options = merge({\n timeout: 45e3\n }, options); // Allow an optional user-specified function to modify the option\n // object before we construct the xhr request\n // TODO: Remove beforeRequest in the next major release.\n\n const beforeRequest = XhrFunction.beforeRequest || videojs.Vhs.xhr.beforeRequest; // onRequest and onResponse hooks as a Set, at either the player or global level.\n // TODO: new Set added here for beforeRequest alias. Remove this when beforeRequest is removed.\n\n const _requestCallbackSet = XhrFunction._requestCallbackSet || videojs.Vhs.xhr._requestCallbackSet || new Set();\n\n const _responseCallbackSet = XhrFunction._responseCallbackSet || videojs.Vhs.xhr._responseCallbackSet;\n\n if (beforeRequest && typeof beforeRequest === 'function') {\n videojs.log.warn('beforeRequest is deprecated, use onRequest instead.');\n\n _requestCallbackSet.add(beforeRequest);\n } // Use the standard videojs.xhr() method unless `videojs.Vhs.xhr` has been overriden\n // TODO: switch back to videojs.Vhs.xhr.name === 'XhrFunction' when we drop IE11\n\n\n const xhrMethod = videojs.Vhs.xhr.original === true ? videojs.xhr : videojs.Vhs.xhr; // call all registered onRequest hooks, assign new options.\n\n const beforeRequestOptions = callAllRequestHooks(_requestCallbackSet, options); // Remove the beforeRequest function from the hooks set so stale beforeRequest functions are not called.\n\n _requestCallbackSet.delete(beforeRequest); // xhrMethod will call XMLHttpRequest.open and XMLHttpRequest.send\n\n\n const request = xhrMethod(beforeRequestOptions || options, function (error, response) {\n // call all registered onResponse hooks\n callAllResponseHooks(_responseCallbackSet, request, error, response);\n return callbackWrapper(request, error, response, callback);\n });\n const originalAbort = request.abort;\n\n request.abort = function () {\n request.aborted = true;\n return originalAbort.apply(request, arguments);\n };\n\n request.uri = options.uri;\n request.requestType = options.requestType;\n request.requestTime = Date.now();\n return request;\n };\n\n xhr.original = true;\n return xhr;\n};\n/**\n * Turns segment byterange into a string suitable for use in\n * HTTP Range requests\n *\n * @param {Object} byterange - an object with two values defining the start and end\n * of a byte-range\n */\n\n\nconst byterangeStr = function (byterange) {\n // `byterangeEnd` is one less than `offset + length` because the HTTP range\n // header uses inclusive ranges\n let byterangeEnd;\n const byterangeStart = byterange.offset;\n\n if (typeof byterange.offset === 'bigint' || typeof byterange.length === 'bigint') {\n byterangeEnd = window$1.BigInt(byterange.offset) + window$1.BigInt(byterange.length) - window$1.BigInt(1);\n } else {\n byterangeEnd = byterange.offset + byterange.length - 1;\n }\n\n return 'bytes=' + byterangeStart + '-' + byterangeEnd;\n};\n/**\n * Defines headers for use in the xhr request for a particular segment.\n *\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n */\n\nconst segmentXhrHeaders = function (segment) {\n const headers = {};\n\n if (segment.byterange) {\n headers.Range = byterangeStr(segment.byterange);\n }\n\n return headers;\n};\n\n/**\n * @file bin-utils.js\n */\n\n/**\n * convert a TimeRange to text\n *\n * @param {TimeRange} range the timerange to use for conversion\n * @param {number} i the iterator on the range to convert\n * @return {string} the range in string format\n */\n\nconst textRange = function (range, i) {\n return range.start(i) + '-' + range.end(i);\n};\n/**\n * format a number as hex string\n *\n * @param {number} e The number\n * @param {number} i the iterator\n * @return {string} the hex formatted number as a string\n */\n\n\nconst formatHexString = function (e, i) {\n const value = e.toString(16);\n return '00'.substring(0, 2 - value.length) + value + (i % 2 ? ' ' : '');\n};\n\nconst formatAsciiString = function (e) {\n if (e >= 0x20 && e < 0x7e) {\n return String.fromCharCode(e);\n }\n\n return '.';\n};\n/**\n * Creates an object for sending to a web worker modifying properties that are TypedArrays\n * into a new object with seperated properties for the buffer, byteOffset, and byteLength.\n *\n * @param {Object} message\n * Object of properties and values to send to the web worker\n * @return {Object}\n * Modified message with TypedArray values expanded\n * @function createTransferableMessage\n */\n\n\nconst createTransferableMessage = function (message) {\n const transferable = {};\n Object.keys(message).forEach(key => {\n const value = message[key];\n\n if (isArrayBufferView(value)) {\n transferable[key] = {\n bytes: value.buffer,\n byteOffset: value.byteOffset,\n byteLength: value.byteLength\n };\n } else {\n transferable[key] = value;\n }\n });\n return transferable;\n};\n/**\n * Returns a unique string identifier for a media initialization\n * segment.\n *\n * @param {Object} initSegment\n * the init segment object.\n *\n * @return {string} the generated init segment id\n */\n\nconst initSegmentId = function (initSegment) {\n const byterange = initSegment.byterange || {\n length: Infinity,\n offset: 0\n };\n return [byterange.length, byterange.offset, initSegment.resolvedUri].join(',');\n};\n/**\n * Returns a unique string identifier for a media segment key.\n *\n * @param {Object} key the encryption key\n * @return {string} the unique id for the media segment key.\n */\n\nconst segmentKeyId = function (key) {\n return key.resolvedUri;\n};\n/**\n * utils to help dump binary data to the console\n *\n * @param {Array|TypedArray} data\n * data to dump to a string\n *\n * @return {string} the data as a hex string.\n */\n\nconst hexDump = data => {\n const bytes = Array.prototype.slice.call(data);\n const step = 16;\n let result = '';\n let hex;\n let ascii;\n\n for (let j = 0; j < bytes.length / step; j++) {\n hex = bytes.slice(j * step, j * step + step).map(formatHexString).join('');\n ascii = bytes.slice(j * step, j * step + step).map(formatAsciiString).join('');\n result += hex + ' ' + ascii + '\\n';\n }\n\n return result;\n};\nconst tagDump = ({\n bytes\n}) => hexDump(bytes);\nconst textRanges = ranges => {\n let result = '';\n let i;\n\n for (i = 0; i < ranges.length; i++) {\n result += textRange(ranges, i) + ' ';\n }\n\n return result;\n};\n\nvar utils = /*#__PURE__*/Object.freeze({\n __proto__: null,\n createTransferableMessage: createTransferableMessage,\n initSegmentId: initSegmentId,\n segmentKeyId: segmentKeyId,\n hexDump: hexDump,\n tagDump: tagDump,\n textRanges: textRanges\n});\n\n// TODO handle fmp4 case where the timing info is accurate and doesn't involve transmux\n// 25% was arbitrarily chosen, and may need to be refined over time.\n\nconst SEGMENT_END_FUDGE_PERCENT = 0.25;\n/**\n * Converts a player time (any time that can be gotten/set from player.currentTime(),\n * e.g., any time within player.seekable().start(0) to player.seekable().end(0)) to a\n * program time (any time referencing the real world (e.g., EXT-X-PROGRAM-DATE-TIME)).\n *\n * The containing segment is required as the EXT-X-PROGRAM-DATE-TIME serves as an \"anchor\n * point\" (a point where we have a mapping from program time to player time, with player\n * time being the post transmux start of the segment).\n *\n * For more details, see [this doc](../../docs/program-time-from-player-time.md).\n *\n * @param {number} playerTime the player time\n * @param {Object} segment the segment which contains the player time\n * @return {Date} program time\n */\n\nconst playerTimeToProgramTime = (playerTime, segment) => {\n if (!segment.dateTimeObject) {\n // Can't convert without an \"anchor point\" for the program time (i.e., a time that can\n // be used to map the start of a segment with a real world time).\n return null;\n }\n\n const transmuxerPrependedSeconds = segment.videoTimingInfo.transmuxerPrependedSeconds;\n const transmuxedStart = segment.videoTimingInfo.transmuxedPresentationStart; // get the start of the content from before old content is prepended\n\n const startOfSegment = transmuxedStart + transmuxerPrependedSeconds;\n const offsetFromSegmentStart = playerTime - startOfSegment;\n return new Date(segment.dateTimeObject.getTime() + offsetFromSegmentStart * 1000);\n};\nconst originalSegmentVideoDuration = videoTimingInfo => {\n return videoTimingInfo.transmuxedPresentationEnd - videoTimingInfo.transmuxedPresentationStart - videoTimingInfo.transmuxerPrependedSeconds;\n};\n/**\n * Finds a segment that contains the time requested given as an ISO-8601 string. The\n * returned segment might be an estimate or an accurate match.\n *\n * @param {string} programTime The ISO-8601 programTime to find a match for\n * @param {Object} playlist A playlist object to search within\n */\n\nconst findSegmentForProgramTime = (programTime, playlist) => {\n // Assumptions:\n // - verifyProgramDateTimeTags has already been run\n // - live streams have been started\n let dateTimeObject;\n\n try {\n dateTimeObject = new Date(programTime);\n } catch (e) {\n return null;\n }\n\n if (!playlist || !playlist.segments || playlist.segments.length === 0) {\n return null;\n }\n\n let segment = playlist.segments[0];\n\n if (dateTimeObject < new Date(segment.dateTimeObject)) {\n // Requested time is before stream start.\n return null;\n }\n\n for (let i = 0; i < playlist.segments.length - 1; i++) {\n segment = playlist.segments[i];\n const nextSegmentStart = new Date(playlist.segments[i + 1].dateTimeObject);\n\n if (dateTimeObject < nextSegmentStart) {\n break;\n }\n }\n\n const lastSegment = playlist.segments[playlist.segments.length - 1];\n const lastSegmentStart = lastSegment.dateTimeObject;\n const lastSegmentDuration = lastSegment.videoTimingInfo ? originalSegmentVideoDuration(lastSegment.videoTimingInfo) : lastSegment.duration + lastSegment.duration * SEGMENT_END_FUDGE_PERCENT;\n const lastSegmentEnd = new Date(lastSegmentStart.getTime() + lastSegmentDuration * 1000);\n\n if (dateTimeObject > lastSegmentEnd) {\n // Beyond the end of the stream, or our best guess of the end of the stream.\n return null;\n }\n\n if (dateTimeObject > new Date(lastSegmentStart)) {\n segment = lastSegment;\n }\n\n return {\n segment,\n estimatedStart: segment.videoTimingInfo ? segment.videoTimingInfo.transmuxedPresentationStart : Playlist.duration(playlist, playlist.mediaSequence + playlist.segments.indexOf(segment)),\n // Although, given that all segments have accurate date time objects, the segment\n // selected should be accurate, unless the video has been transmuxed at some point\n // (determined by the presence of the videoTimingInfo object), the segment's \"player\n // time\" (the start time in the player) can't be considered accurate.\n type: segment.videoTimingInfo ? 'accurate' : 'estimate'\n };\n};\n/**\n * Finds a segment that contains the given player time(in seconds).\n *\n * @param {number} time The player time to find a match for\n * @param {Object} playlist A playlist object to search within\n */\n\nconst findSegmentForPlayerTime = (time, playlist) => {\n // Assumptions:\n // - there will always be a segment.duration\n // - we can start from zero\n // - segments are in time order\n if (!playlist || !playlist.segments || playlist.segments.length === 0) {\n return null;\n }\n\n let segmentEnd = 0;\n let segment;\n\n for (let i = 0; i < playlist.segments.length; i++) {\n segment = playlist.segments[i]; // videoTimingInfo is set after the segment is downloaded and transmuxed, and\n // should contain the most accurate values we have for the segment's player times.\n //\n // Use the accurate transmuxedPresentationEnd value if it is available, otherwise fall\n // back to an estimate based on the manifest derived (inaccurate) segment.duration, to\n // calculate an end value.\n\n segmentEnd = segment.videoTimingInfo ? segment.videoTimingInfo.transmuxedPresentationEnd : segmentEnd + segment.duration;\n\n if (time <= segmentEnd) {\n break;\n }\n }\n\n const lastSegment = playlist.segments[playlist.segments.length - 1];\n\n if (lastSegment.videoTimingInfo && lastSegment.videoTimingInfo.transmuxedPresentationEnd < time) {\n // The time requested is beyond the stream end.\n return null;\n }\n\n if (time > segmentEnd) {\n // The time is within or beyond the last segment.\n //\n // Check to see if the time is beyond a reasonable guess of the end of the stream.\n if (time > segmentEnd + lastSegment.duration * SEGMENT_END_FUDGE_PERCENT) {\n // Technically, because the duration value is only an estimate, the time may still\n // exist in the last segment, however, there isn't enough information to make even\n // a reasonable estimate.\n return null;\n }\n\n segment = lastSegment;\n }\n\n return {\n segment,\n estimatedStart: segment.videoTimingInfo ? segment.videoTimingInfo.transmuxedPresentationStart : segmentEnd - segment.duration,\n // Because videoTimingInfo is only set after transmux, it is the only way to get\n // accurate timing values.\n type: segment.videoTimingInfo ? 'accurate' : 'estimate'\n };\n};\n/**\n * Gives the offset of the comparisonTimestamp from the programTime timestamp in seconds.\n * If the offset returned is positive, the programTime occurs after the\n * comparisonTimestamp.\n * If the offset is negative, the programTime occurs before the comparisonTimestamp.\n *\n * @param {string} comparisonTimeStamp An ISO-8601 timestamp to compare against\n * @param {string} programTime The programTime as an ISO-8601 string\n * @return {number} offset\n */\n\nconst getOffsetFromTimestamp = (comparisonTimeStamp, programTime) => {\n let segmentDateTime;\n let programDateTime;\n\n try {\n segmentDateTime = new Date(comparisonTimeStamp);\n programDateTime = new Date(programTime);\n } catch (e) {// TODO handle error\n }\n\n const segmentTimeEpoch = segmentDateTime.getTime();\n const programTimeEpoch = programDateTime.getTime();\n return (programTimeEpoch - segmentTimeEpoch) / 1000;\n};\n/**\n * Checks that all segments in this playlist have programDateTime tags.\n *\n * @param {Object} playlist A playlist object\n */\n\nconst verifyProgramDateTimeTags = playlist => {\n if (!playlist.segments || playlist.segments.length === 0) {\n return false;\n }\n\n for (let i = 0; i < playlist.segments.length; i++) {\n const segment = playlist.segments[i];\n\n if (!segment.dateTimeObject) {\n return false;\n }\n }\n\n return true;\n};\n/**\n * Returns the programTime of the media given a playlist and a playerTime.\n * The playlist must have programDateTime tags for a programDateTime tag to be returned.\n * If the segments containing the time requested have not been buffered yet, an estimate\n * may be returned to the callback.\n *\n * @param {Object} args\n * @param {Object} args.playlist A playlist object to search within\n * @param {number} time A playerTime in seconds\n * @param {Function} callback(err, programTime)\n * @return {string} err.message A detailed error message\n * @return {Object} programTime\n * @return {number} programTime.mediaSeconds The streamTime in seconds\n * @return {string} programTime.programDateTime The programTime as an ISO-8601 String\n */\n\nconst getProgramTime = ({\n playlist,\n time = undefined,\n callback\n}) => {\n if (!callback) {\n throw new Error('getProgramTime: callback must be provided');\n }\n\n if (!playlist || time === undefined) {\n return callback({\n message: 'getProgramTime: playlist and time must be provided'\n });\n }\n\n const matchedSegment = findSegmentForPlayerTime(time, playlist);\n\n if (!matchedSegment) {\n return callback({\n message: 'valid programTime was not found'\n });\n }\n\n if (matchedSegment.type === 'estimate') {\n return callback({\n message: 'Accurate programTime could not be determined.' + ' Please seek to e.seekTime and try again',\n seekTime: matchedSegment.estimatedStart\n });\n }\n\n const programTimeObject = {\n mediaSeconds: time\n };\n const programTime = playerTimeToProgramTime(time, matchedSegment.segment);\n\n if (programTime) {\n programTimeObject.programDateTime = programTime.toISOString();\n }\n\n return callback(null, programTimeObject);\n};\n/**\n * Seeks in the player to a time that matches the given programTime ISO-8601 string.\n *\n * @param {Object} args\n * @param {string} args.programTime A programTime to seek to as an ISO-8601 String\n * @param {Object} args.playlist A playlist to look within\n * @param {number} args.retryCount The number of times to try for an accurate seek. Default is 2.\n * @param {Function} args.seekTo A method to perform a seek\n * @param {boolean} args.pauseAfterSeek Whether to end in a paused state after seeking. Default is true.\n * @param {Object} args.tech The tech to seek on\n * @param {Function} args.callback(err, newTime) A callback to return the new time to\n * @return {string} err.message A detailed error message\n * @return {number} newTime The exact time that was seeked to in seconds\n */\n\nconst seekToProgramTime = ({\n programTime,\n playlist,\n retryCount = 2,\n seekTo,\n pauseAfterSeek = true,\n tech,\n callback\n}) => {\n if (!callback) {\n throw new Error('seekToProgramTime: callback must be provided');\n }\n\n if (typeof programTime === 'undefined' || !playlist || !seekTo) {\n return callback({\n message: 'seekToProgramTime: programTime, seekTo and playlist must be provided'\n });\n }\n\n if (!playlist.endList && !tech.hasStarted_) {\n return callback({\n message: 'player must be playing a live stream to start buffering'\n });\n }\n\n if (!verifyProgramDateTimeTags(playlist)) {\n return callback({\n message: 'programDateTime tags must be provided in the manifest ' + playlist.resolvedUri\n });\n }\n\n const matchedSegment = findSegmentForProgramTime(programTime, playlist); // no match\n\n if (!matchedSegment) {\n return callback({\n message: `${programTime} was not found in the stream`\n });\n }\n\n const segment = matchedSegment.segment;\n const mediaOffset = getOffsetFromTimestamp(segment.dateTimeObject, programTime);\n\n if (matchedSegment.type === 'estimate') {\n // we've run out of retries\n if (retryCount === 0) {\n return callback({\n message: `${programTime} is not buffered yet. Try again`\n });\n }\n\n seekTo(matchedSegment.estimatedStart + mediaOffset);\n tech.one('seeked', () => {\n seekToProgramTime({\n programTime,\n playlist,\n retryCount: retryCount - 1,\n seekTo,\n pauseAfterSeek,\n tech,\n callback\n });\n });\n return;\n } // Since the segment.start value is determined from the buffered end or ending time\n // of the prior segment, the seekToTime doesn't need to account for any transmuxer\n // modifications.\n\n\n const seekToTime = segment.start + mediaOffset;\n\n const seekedCallback = () => {\n return callback(null, tech.currentTime());\n }; // listen for seeked event\n\n\n tech.one('seeked', seekedCallback); // pause before seeking as video.js will restore this state\n\n if (pauseAfterSeek) {\n tech.pause();\n }\n\n seekTo(seekToTime);\n};\n\n// which will only happen if the request is complete.\n\nconst callbackOnCompleted = (request, cb) => {\n if (request.readyState === 4) {\n return cb();\n }\n\n return;\n};\n\nconst containerRequest = (uri, xhr, cb, requestType) => {\n let bytes = [];\n let id3Offset;\n let finished = false;\n\n const endRequestAndCallback = function (err, req, type, _bytes) {\n req.abort();\n finished = true;\n return cb(err, req, type, _bytes);\n };\n\n const progressListener = function (error, request) {\n if (finished) {\n return;\n }\n\n if (error) {\n error.metadata = getStreamingNetworkErrorMetadata({\n requestType,\n request,\n error\n });\n return endRequestAndCallback(error, request, '', bytes);\n } // grap the new part of content that was just downloaded\n\n\n const newPart = request.responseText.substring(bytes && bytes.byteLength || 0, request.responseText.length); // add that onto bytes\n\n bytes = concatTypedArrays(bytes, stringToBytes(newPart, true));\n id3Offset = id3Offset || getId3Offset(bytes); // we need at least 10 bytes to determine a type\n // or we need at least two bytes after an id3Offset\n\n if (bytes.length < 10 || id3Offset && bytes.length < id3Offset + 2) {\n return callbackOnCompleted(request, () => endRequestAndCallback(error, request, '', bytes));\n }\n\n const type = detectContainerForBytes(bytes); // if this looks like a ts segment but we don't have enough data\n // to see the second sync byte, wait until we have enough data\n // before declaring it ts\n\n if (type === 'ts' && bytes.length < 188) {\n return callbackOnCompleted(request, () => endRequestAndCallback(error, request, '', bytes));\n } // this may be an unsynced ts segment\n // wait for 376 bytes before detecting no container\n\n\n if (!type && bytes.length < 376) {\n return callbackOnCompleted(request, () => endRequestAndCallback(error, request, '', bytes));\n }\n\n return endRequestAndCallback(null, request, type, bytes);\n };\n\n const options = {\n uri,\n\n beforeSend(request) {\n // this forces the browser to pass the bytes to us unprocessed\n request.overrideMimeType('text/plain; charset=x-user-defined');\n request.addEventListener('progress', function ({\n total,\n loaded\n }) {\n return callbackWrapper(request, null, {\n statusCode: request.status\n }, progressListener);\n });\n }\n\n };\n const request = xhr(options, function (error, response) {\n return callbackWrapper(request, error, response, progressListener);\n });\n return request;\n};\n\nconst {\n EventTarget\n} = videojs;\n\nconst dashPlaylistUnchanged = function (a, b) {\n if (!isPlaylistUnchanged(a, b)) {\n return false;\n } // for dash the above check will often return true in scenarios where\n // the playlist actually has changed because mediaSequence isn't a\n // dash thing, and we often set it to 1. So if the playlists have the same amount\n // of segments we return true.\n // So for dash we need to make sure that the underlying segments are different.\n // if sidx changed then the playlists are different.\n\n\n if (a.sidx && b.sidx && (a.sidx.offset !== b.sidx.offset || a.sidx.length !== b.sidx.length)) {\n return false;\n } else if (!a.sidx && b.sidx || a.sidx && !b.sidx) {\n return false;\n } // one or the other does not have segments\n // there was a change.\n\n\n if (a.segments && !b.segments || !a.segments && b.segments) {\n return false;\n } // neither has segments nothing changed\n\n\n if (!a.segments && !b.segments) {\n return true;\n } // check segments themselves\n\n\n for (let i = 0; i < a.segments.length; i++) {\n const aSegment = a.segments[i];\n const bSegment = b.segments[i]; // if uris are different between segments there was a change\n\n if (aSegment.uri !== bSegment.uri) {\n return false;\n } // neither segment has a byterange, there will be no byterange change.\n\n\n if (!aSegment.byterange && !bSegment.byterange) {\n continue;\n }\n\n const aByterange = aSegment.byterange;\n const bByterange = bSegment.byterange; // if byterange only exists on one of the segments, there was a change.\n\n if (aByterange && !bByterange || !aByterange && bByterange) {\n return false;\n } // if both segments have byterange with different offsets, there was a change.\n\n\n if (aByterange.offset !== bByterange.offset || aByterange.length !== bByterange.length) {\n return false;\n }\n } // if everything was the same with segments, this is the same playlist.\n\n\n return true;\n};\n/**\n * Use the representation IDs from the mpd object to create groupIDs, the NAME is set to mandatory representation\n * ID in the parser. This allows for continuous playout across periods with the same representation IDs\n * (continuous periods as defined in DASH-IF 3.2.12). This is assumed in the mpd-parser as well. If we want to support\n * periods without continuous playback this function may need modification as well as the parser.\n */\n\n\nconst dashGroupId = (type, group, label, playlist) => {\n // If the manifest somehow does not have an ID (non-dash compliant), use the label.\n const playlistId = playlist.attributes.NAME || label;\n return `placeholder-uri-${type}-${group}-${playlistId}`;\n};\n/**\n * Parses the main XML string and updates playlist URI references.\n *\n * @param {Object} config\n * Object of arguments\n * @param {string} config.mainXml\n * The mpd XML\n * @param {string} config.srcUrl\n * The mpd URL\n * @param {Date} config.clientOffset\n * A time difference between server and client\n * @param {Object} config.sidxMapping\n * SIDX mappings for moof/mdat URIs and byte ranges\n * @return {Object}\n * The parsed mpd manifest object\n */\n\n\nconst parseMainXml = ({\n mainXml,\n srcUrl,\n clientOffset,\n sidxMapping,\n previousManifest\n}) => {\n const manifest = parse(mainXml, {\n manifestUri: srcUrl,\n clientOffset,\n sidxMapping,\n previousManifest\n });\n addPropertiesToMain(manifest, srcUrl, dashGroupId);\n return manifest;\n};\n/**\n * Removes any mediaGroup labels that no longer exist in the newMain\n *\n * @param {Object} update\n * The previous mpd object being updated\n * @param {Object} newMain\n * The new mpd object\n */\n\nconst removeOldMediaGroupLabels = (update, newMain) => {\n forEachMediaGroup(update, (properties, type, group, label) => {\n if (!newMain.mediaGroups[type][group] || !(label in newMain.mediaGroups[type][group])) {\n delete update.mediaGroups[type][group][label];\n }\n });\n};\n/**\n * Returns a new main manifest that is the result of merging an updated main manifest\n * into the original version.\n *\n * @param {Object} oldMain\n * The old parsed mpd object\n * @param {Object} newMain\n * The updated parsed mpd object\n * @return {Object}\n * A new object representing the original main manifest with the updated media\n * playlists merged in\n */\n\n\nconst updateMain = (oldMain, newMain, sidxMapping) => {\n let noChanges = true;\n let update = merge(oldMain, {\n // These are top level properties that can be updated\n duration: newMain.duration,\n minimumUpdatePeriod: newMain.minimumUpdatePeriod,\n timelineStarts: newMain.timelineStarts\n }); // First update the playlists in playlist list\n\n for (let i = 0; i < newMain.playlists.length; i++) {\n const playlist = newMain.playlists[i];\n\n if (playlist.sidx) {\n const sidxKey = generateSidxKey(playlist.sidx); // add sidx segments to the playlist if we have all the sidx info already\n\n if (sidxMapping && sidxMapping[sidxKey] && sidxMapping[sidxKey].sidx) {\n addSidxSegmentsToPlaylist(playlist, sidxMapping[sidxKey].sidx, playlist.sidx.resolvedUri);\n }\n }\n\n const playlistUpdate = updateMain$1(update, playlist, dashPlaylistUnchanged);\n\n if (playlistUpdate) {\n update = playlistUpdate;\n noChanges = false;\n }\n } // Then update media group playlists\n\n\n forEachMediaGroup(newMain, (properties, type, group, label) => {\n if (properties.playlists && properties.playlists.length) {\n const id = properties.playlists[0].id;\n const playlistUpdate = updateMain$1(update, properties.playlists[0], dashPlaylistUnchanged);\n\n if (playlistUpdate) {\n update = playlistUpdate; // add new mediaGroup label if it doesn't exist and assign the new mediaGroup.\n\n if (!(label in update.mediaGroups[type][group])) {\n update.mediaGroups[type][group][label] = properties;\n } // update the playlist reference within media groups\n\n\n update.mediaGroups[type][group][label].playlists[0] = update.playlists[id];\n noChanges = false;\n }\n }\n }); // remove mediaGroup labels and references that no longer exist in the newMain\n\n removeOldMediaGroupLabels(update, newMain);\n\n if (newMain.minimumUpdatePeriod !== oldMain.minimumUpdatePeriod) {\n noChanges = false;\n }\n\n if (noChanges) {\n return null;\n }\n\n return update;\n}; // SIDX should be equivalent if the URI and byteranges of the SIDX match.\n// If the SIDXs have maps, the two maps should match,\n// both `a` and `b` missing SIDXs is considered matching.\n// If `a` or `b` but not both have a map, they aren't matching.\n\nconst equivalentSidx = (a, b) => {\n const neitherMap = Boolean(!a.map && !b.map);\n const equivalentMap = neitherMap || Boolean(a.map && b.map && a.map.byterange.offset === b.map.byterange.offset && a.map.byterange.length === b.map.byterange.length);\n return equivalentMap && a.uri === b.uri && a.byterange.offset === b.byterange.offset && a.byterange.length === b.byterange.length;\n}; // exported for testing\n\n\nconst compareSidxEntry = (playlists, oldSidxMapping) => {\n const newSidxMapping = {};\n\n for (const id in playlists) {\n const playlist = playlists[id];\n const currentSidxInfo = playlist.sidx;\n\n if (currentSidxInfo) {\n const key = generateSidxKey(currentSidxInfo);\n\n if (!oldSidxMapping[key]) {\n break;\n }\n\n const savedSidxInfo = oldSidxMapping[key].sidxInfo;\n\n if (equivalentSidx(savedSidxInfo, currentSidxInfo)) {\n newSidxMapping[key] = oldSidxMapping[key];\n }\n }\n }\n\n return newSidxMapping;\n};\n/**\n * A function that filters out changed items as they need to be requested separately.\n *\n * The method is exported for testing\n *\n * @param {Object} main the parsed mpd XML returned via mpd-parser\n * @param {Object} oldSidxMapping the SIDX to compare against\n */\n\nconst filterChangedSidxMappings = (main, oldSidxMapping) => {\n const videoSidx = compareSidxEntry(main.playlists, oldSidxMapping);\n let mediaGroupSidx = videoSidx;\n forEachMediaGroup(main, (properties, mediaType, groupKey, labelKey) => {\n if (properties.playlists && properties.playlists.length) {\n const playlists = properties.playlists;\n mediaGroupSidx = merge(mediaGroupSidx, compareSidxEntry(playlists, oldSidxMapping));\n }\n });\n return mediaGroupSidx;\n};\nclass DashPlaylistLoader extends EventTarget {\n // DashPlaylistLoader must accept either a src url or a playlist because subsequent\n // playlist loader setups from media groups will expect to be able to pass a playlist\n // (since there aren't external URLs to media playlists with DASH)\n constructor(srcUrlOrPlaylist, vhs, options = {}, mainPlaylistLoader) {\n super();\n this.isPaused_ = true;\n this.mainPlaylistLoader_ = mainPlaylistLoader || this;\n\n if (!mainPlaylistLoader) {\n this.isMain_ = true;\n }\n\n const {\n withCredentials = false\n } = options;\n this.vhs_ = vhs;\n this.withCredentials = withCredentials;\n this.addMetadataToTextTrack = options.addMetadataToTextTrack;\n\n if (!srcUrlOrPlaylist) {\n throw new Error('A non-empty playlist URL or object is required');\n } // event naming?\n\n\n this.on('minimumUpdatePeriod', () => {\n this.refreshXml_();\n }); // live playlist staleness timeout\n\n this.on('mediaupdatetimeout', () => {\n this.refreshMedia_(this.media().id);\n });\n this.state = 'HAVE_NOTHING';\n this.loadedPlaylists_ = {};\n this.logger_ = logger('DashPlaylistLoader'); // initialize the loader state\n // The mainPlaylistLoader will be created with a string\n\n if (this.isMain_) {\n this.mainPlaylistLoader_.srcUrl = srcUrlOrPlaylist; // TODO: reset sidxMapping between period changes\n // once multi-period is refactored\n\n this.mainPlaylistLoader_.sidxMapping_ = {};\n } else {\n this.childPlaylist_ = srcUrlOrPlaylist;\n }\n }\n\n get isPaused() {\n return this.isPaused_;\n }\n\n requestErrored_(err, request, startingState) {\n // disposed\n if (!this.request) {\n return true;\n } // pending request is cleared\n\n\n this.request = null;\n\n if (err) {\n // use the provided error object or create one\n // based on the request/response\n this.error = typeof err === 'object' && !(err instanceof Error) ? err : {\n status: request.status,\n message: 'DASH request error at URL: ' + request.uri,\n response: request.response,\n // MEDIA_ERR_NETWORK\n code: 2,\n metadata: err.metadata\n };\n\n if (startingState) {\n this.state = startingState;\n }\n\n this.trigger('error');\n return true;\n }\n }\n /**\n * Verify that the container of the sidx segment can be parsed\n * and if it can, get and parse that segment.\n */\n\n\n addSidxSegments_(playlist, startingState, cb) {\n const sidxKey = playlist.sidx && generateSidxKey(playlist.sidx); // playlist lacks sidx or sidx segments were added to this playlist already.\n\n if (!playlist.sidx || !sidxKey || this.mainPlaylistLoader_.sidxMapping_[sidxKey]) {\n // keep this function async\n window$1.clearTimeout(this.mediaRequest_);\n this.mediaRequest_ = window$1.setTimeout(() => cb(false), 0);\n return;\n } // resolve the segment URL relative to the playlist\n\n\n const uri = resolveManifestRedirect(playlist.sidx.resolvedUri);\n\n const fin = (err, request) => {\n if (this.requestErrored_(err, request, startingState)) {\n return;\n }\n\n const sidxMapping = this.mainPlaylistLoader_.sidxMapping_;\n const {\n requestType\n } = request;\n let sidx;\n\n try {\n sidx = parseSidx(toUint8(request.response).subarray(8));\n } catch (e) {\n e.metadata = getStreamingNetworkErrorMetadata({\n requestType,\n request,\n parseFailure: true\n }); // sidx parsing failed.\n\n this.requestErrored_(e, request, startingState);\n return;\n }\n\n sidxMapping[sidxKey] = {\n sidxInfo: playlist.sidx,\n sidx\n };\n addSidxSegmentsToPlaylist(playlist, sidx, playlist.sidx.resolvedUri);\n return cb(true);\n };\n\n const REQUEST_TYPE = 'dash-sidx';\n this.request = containerRequest(uri, this.vhs_.xhr, (err, request, container, bytes) => {\n if (err) {\n return fin(err, request);\n }\n\n if (!container || container !== 'mp4') {\n const sidxContainer = container || 'unknown';\n return fin({\n status: request.status,\n message: `Unsupported ${sidxContainer} container type for sidx segment at URL: ${uri}`,\n // response is just bytes in this case\n // but we really don't want to return that.\n response: '',\n playlist,\n internal: true,\n playlistExclusionDuration: Infinity,\n // MEDIA_ERR_NETWORK\n code: 2\n }, request);\n } // if we already downloaded the sidx bytes in the container request, use them\n\n\n const {\n offset,\n length\n } = playlist.sidx.byterange;\n\n if (bytes.length >= length + offset) {\n return fin(err, {\n response: bytes.subarray(offset, offset + length),\n status: request.status,\n uri: request.uri\n });\n } // otherwise request sidx bytes\n\n\n this.request = this.vhs_.xhr({\n uri,\n responseType: 'arraybuffer',\n requestType: 'dash-sidx',\n headers: segmentXhrHeaders({\n byterange: playlist.sidx.byterange\n })\n }, fin);\n }, REQUEST_TYPE);\n }\n\n dispose() {\n this.isPaused_ = true;\n this.trigger('dispose');\n this.stopRequest();\n this.loadedPlaylists_ = {};\n window$1.clearTimeout(this.minimumUpdatePeriodTimeout_);\n window$1.clearTimeout(this.mediaRequest_);\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n this.mediaRequest_ = null;\n this.minimumUpdatePeriodTimeout_ = null;\n\n if (this.mainPlaylistLoader_.createMupOnMedia_) {\n this.off('loadedmetadata', this.mainPlaylistLoader_.createMupOnMedia_);\n this.mainPlaylistLoader_.createMupOnMedia_ = null;\n }\n\n this.off();\n }\n\n hasPendingRequest() {\n return this.request || this.mediaRequest_;\n }\n\n stopRequest() {\n if (this.request) {\n const oldRequest = this.request;\n this.request = null;\n oldRequest.onreadystatechange = null;\n oldRequest.abort();\n }\n }\n\n media(playlist) {\n // getter\n if (!playlist) {\n return this.media_;\n } // setter\n\n\n if (this.state === 'HAVE_NOTHING') {\n throw new Error('Cannot switch media playlist from ' + this.state);\n }\n\n const startingState = this.state; // find the playlist object if the target playlist has been specified by URI\n\n if (typeof playlist === 'string') {\n if (!this.mainPlaylistLoader_.main.playlists[playlist]) {\n throw new Error('Unknown playlist URI: ' + playlist);\n }\n\n playlist = this.mainPlaylistLoader_.main.playlists[playlist];\n }\n\n const mediaChange = !this.media_ || playlist.id !== this.media_.id; // switch to previously loaded playlists immediately\n\n if (mediaChange && this.loadedPlaylists_[playlist.id] && this.loadedPlaylists_[playlist.id].endList) {\n this.state = 'HAVE_METADATA';\n this.media_ = playlist; // trigger media change if the active media has been updated\n\n if (mediaChange) {\n this.trigger('mediachanging');\n this.trigger('mediachange');\n }\n\n return;\n } // switching to the active playlist is a no-op\n\n\n if (!mediaChange) {\n return;\n } // switching from an already loaded playlist\n\n\n if (this.media_) {\n this.trigger('mediachanging');\n }\n\n this.addSidxSegments_(playlist, startingState, sidxChanged => {\n // everything is ready just continue to haveMetadata\n this.haveMetadata({\n startingState,\n playlist\n });\n });\n }\n\n haveMetadata({\n startingState,\n playlist\n }) {\n this.state = 'HAVE_METADATA';\n this.loadedPlaylists_[playlist.id] = playlist;\n window$1.clearTimeout(this.mediaRequest_);\n this.mediaRequest_ = null; // This will trigger loadedplaylist\n\n this.refreshMedia_(playlist.id); // fire loadedmetadata the first time a media playlist is loaded\n // to resolve setup of media groups\n\n if (startingState === 'HAVE_MAIN_MANIFEST') {\n this.trigger('loadedmetadata');\n } else {\n // trigger media change if the active media has been updated\n this.trigger('mediachange');\n }\n }\n\n pause() {\n this.isPaused_ = true;\n\n if (this.mainPlaylistLoader_.createMupOnMedia_) {\n this.off('loadedmetadata', this.mainPlaylistLoader_.createMupOnMedia_);\n this.mainPlaylistLoader_.createMupOnMedia_ = null;\n }\n\n this.stopRequest();\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n\n if (this.isMain_) {\n window$1.clearTimeout(this.mainPlaylistLoader_.minimumUpdatePeriodTimeout_);\n this.mainPlaylistLoader_.minimumUpdatePeriodTimeout_ = null;\n }\n\n if (this.state === 'HAVE_NOTHING') {\n // If we pause the loader before any data has been retrieved, its as if we never\n // started, so reset to an unstarted state.\n this.started = false;\n }\n }\n\n load(isFinalRendition) {\n this.isPaused_ = false;\n window$1.clearTimeout(this.mediaUpdateTimeout);\n this.mediaUpdateTimeout = null;\n const media = this.media();\n\n if (isFinalRendition) {\n const delay = media ? media.targetDuration / 2 * 1000 : 5 * 1000;\n this.mediaUpdateTimeout = window$1.setTimeout(() => this.load(), delay);\n return;\n } // because the playlists are internal to the manifest, load should either load the\n // main manifest, or do nothing but trigger an event\n\n\n if (!this.started) {\n this.start();\n return;\n }\n\n if (media && !media.endList) {\n // Check to see if this is the main loader and the MUP was cleared (this happens\n // when the loader was paused). `media` should be set at this point since one is always\n // set during `start()`.\n if (this.isMain_ && !this.minimumUpdatePeriodTimeout_) {\n // Trigger minimumUpdatePeriod to refresh the main manifest\n this.trigger('minimumUpdatePeriod'); // Since there was no prior minimumUpdatePeriodTimeout it should be recreated\n\n this.updateMinimumUpdatePeriodTimeout_();\n }\n\n this.trigger('mediaupdatetimeout');\n } else {\n this.trigger('loadedplaylist');\n }\n }\n\n start() {\n this.started = true; // We don't need to request the main manifest again\n // Call this asynchronously to match the xhr request behavior below\n\n if (!this.isMain_) {\n window$1.clearTimeout(this.mediaRequest_);\n this.mediaRequest_ = window$1.setTimeout(() => this.haveMain_(), 0);\n return;\n }\n\n this.requestMain_((req, mainChanged) => {\n this.haveMain_();\n\n if (!this.hasPendingRequest() && !this.media_) {\n this.media(this.mainPlaylistLoader_.main.playlists[0]);\n }\n });\n }\n\n requestMain_(cb) {\n const metadata = {\n manifestInfo: {\n uri: this.mainPlaylistLoader_.srcUrl\n }\n };\n this.trigger({\n type: 'manifestrequeststart',\n metadata\n });\n this.request = this.vhs_.xhr({\n uri: this.mainPlaylistLoader_.srcUrl,\n withCredentials: this.withCredentials,\n requestType: 'dash-manifest'\n }, (error, req) => {\n if (error) {\n const {\n requestType\n } = req;\n error.metadata = getStreamingNetworkErrorMetadata({\n requestType,\n request: req,\n error\n });\n }\n\n if (this.requestErrored_(error, req)) {\n if (this.state === 'HAVE_NOTHING') {\n this.started = false;\n }\n\n return;\n }\n\n this.trigger({\n type: 'manifestrequestcomplete',\n metadata\n });\n const mainChanged = req.responseText !== this.mainPlaylistLoader_.mainXml_;\n this.mainPlaylistLoader_.mainXml_ = req.responseText;\n\n if (req.responseHeaders && req.responseHeaders.date) {\n this.mainLoaded_ = Date.parse(req.responseHeaders.date);\n } else {\n this.mainLoaded_ = Date.now();\n }\n\n this.mainPlaylistLoader_.srcUrl = resolveManifestRedirect(this.mainPlaylistLoader_.srcUrl, req);\n\n if (mainChanged) {\n this.handleMain_();\n this.syncClientServerClock_(() => {\n return cb(req, mainChanged);\n });\n return;\n }\n\n return cb(req, mainChanged);\n });\n }\n /**\n * Parses the main xml for UTCTiming node to sync the client clock to the server\n * clock. If the UTCTiming node requires a HEAD or GET request, that request is made.\n *\n * @param {Function} done\n * Function to call when clock sync has completed\n */\n\n\n syncClientServerClock_(done) {\n const utcTiming = parseUTCTiming(this.mainPlaylistLoader_.mainXml_); // No UTCTiming element found in the mpd. Use Date header from mpd request as the\n // server clock\n\n if (utcTiming === null) {\n this.mainPlaylistLoader_.clientOffset_ = this.mainLoaded_ - Date.now();\n return done();\n }\n\n if (utcTiming.method === 'DIRECT') {\n this.mainPlaylistLoader_.clientOffset_ = utcTiming.value - Date.now();\n return done();\n }\n\n this.request = this.vhs_.xhr({\n uri: resolveUrl(this.mainPlaylistLoader_.srcUrl, utcTiming.value),\n method: utcTiming.method,\n withCredentials: this.withCredentials,\n requestType: 'dash-clock-sync'\n }, (error, req) => {\n // disposed\n if (!this.request) {\n return;\n }\n\n if (error) {\n const {\n requestType\n } = req;\n this.error.metadata = getStreamingNetworkErrorMetadata({\n requestType,\n request: req,\n error\n }); // sync request failed, fall back to using date header from mpd\n // TODO: log warning\n\n this.mainPlaylistLoader_.clientOffset_ = this.mainLoaded_ - Date.now();\n return done();\n }\n\n let serverTime;\n\n if (utcTiming.method === 'HEAD') {\n if (!req.responseHeaders || !req.responseHeaders.date) {\n // expected date header not preset, fall back to using date header from mpd\n // TODO: log warning\n serverTime = this.mainLoaded_;\n } else {\n serverTime = Date.parse(req.responseHeaders.date);\n }\n } else {\n serverTime = Date.parse(req.responseText);\n }\n\n this.mainPlaylistLoader_.clientOffset_ = serverTime - Date.now();\n done();\n });\n }\n\n haveMain_() {\n this.state = 'HAVE_MAIN_MANIFEST';\n\n if (this.isMain_) {\n // We have the main playlist at this point, so\n // trigger this to allow PlaylistController\n // to make an initial playlist selection\n this.trigger('loadedplaylist');\n } else if (!this.media_) {\n // no media playlist was specifically selected so select\n // the one the child playlist loader was created with\n this.media(this.childPlaylist_);\n }\n }\n\n handleMain_() {\n // clear media request\n window$1.clearTimeout(this.mediaRequest_);\n this.mediaRequest_ = null;\n const oldMain = this.mainPlaylistLoader_.main;\n const metadata = {\n manifestInfo: {\n uri: this.mainPlaylistLoader_.srcUrl\n }\n };\n this.trigger({\n type: 'manifestparsestart',\n metadata\n });\n let newMain;\n\n try {\n newMain = parseMainXml({\n mainXml: this.mainPlaylistLoader_.mainXml_,\n srcUrl: this.mainPlaylistLoader_.srcUrl,\n clientOffset: this.mainPlaylistLoader_.clientOffset_,\n sidxMapping: this.mainPlaylistLoader_.sidxMapping_,\n previousManifest: oldMain\n });\n } catch (error) {\n this.error = error;\n this.error.metadata = {\n errorType: videojs.Error.StreamingDashManifestParserError,\n error\n };\n this.trigger('error');\n } // if we have an old main to compare the new main against\n\n\n if (oldMain) {\n newMain = updateMain(oldMain, newMain, this.mainPlaylistLoader_.sidxMapping_);\n } // only update main if we have a new main\n\n\n this.mainPlaylistLoader_.main = newMain ? newMain : oldMain;\n const location = this.mainPlaylistLoader_.main.locations && this.mainPlaylistLoader_.main.locations[0];\n\n if (location && location !== this.mainPlaylistLoader_.srcUrl) {\n this.mainPlaylistLoader_.srcUrl = location;\n }\n\n if (!oldMain || newMain && newMain.minimumUpdatePeriod !== oldMain.minimumUpdatePeriod) {\n this.updateMinimumUpdatePeriodTimeout_();\n }\n\n this.addEventStreamToMetadataTrack_(newMain);\n\n if (newMain) {\n const {\n duration,\n endList\n } = newMain;\n const renditions = [];\n newMain.playlists.forEach(playlist => {\n renditions.push({\n id: playlist.id,\n bandwidth: playlist.attributes.BANDWIDTH,\n resolution: playlist.attributes.RESOLUTION,\n codecs: playlist.attributes.CODECS\n });\n });\n const parsedManifest = {\n duration,\n isLive: !endList,\n renditions\n };\n metadata.parsedManifest = parsedManifest;\n this.trigger({\n type: 'manifestparsecomplete',\n metadata\n });\n }\n\n return Boolean(newMain);\n }\n\n updateMinimumUpdatePeriodTimeout_() {\n const mpl = this.mainPlaylistLoader_; // cancel any pending creation of mup on media\n // a new one will be added if needed.\n\n if (mpl.createMupOnMedia_) {\n mpl.off('loadedmetadata', mpl.createMupOnMedia_);\n mpl.createMupOnMedia_ = null;\n } // clear any pending timeouts\n\n\n if (mpl.minimumUpdatePeriodTimeout_) {\n window$1.clearTimeout(mpl.minimumUpdatePeriodTimeout_);\n mpl.minimumUpdatePeriodTimeout_ = null;\n }\n\n let mup = mpl.main && mpl.main.minimumUpdatePeriod; // If the minimumUpdatePeriod has a value of 0, that indicates that the current\n // MPD has no future validity, so a new one will need to be acquired when new\n // media segments are to be made available. Thus, we use the target duration\n // in this case\n\n if (mup === 0) {\n if (mpl.media()) {\n mup = mpl.media().targetDuration * 1000;\n } else {\n mpl.createMupOnMedia_ = mpl.updateMinimumUpdatePeriodTimeout_;\n mpl.one('loadedmetadata', mpl.createMupOnMedia_);\n }\n } // if minimumUpdatePeriod is invalid or <= zero, which\n // can happen when a live video becomes VOD. skip timeout\n // creation.\n\n\n if (typeof mup !== 'number' || mup <= 0) {\n if (mup < 0) {\n this.logger_(`found invalid minimumUpdatePeriod of ${mup}, not setting a timeout`);\n }\n\n return;\n }\n\n this.createMUPTimeout_(mup);\n }\n\n createMUPTimeout_(mup) {\n const mpl = this.mainPlaylistLoader_;\n mpl.minimumUpdatePeriodTimeout_ = window$1.setTimeout(() => {\n mpl.minimumUpdatePeriodTimeout_ = null;\n mpl.trigger('minimumUpdatePeriod');\n mpl.createMUPTimeout_(mup);\n }, mup);\n }\n /**\n * Sends request to refresh the main xml and updates the parsed main manifest\n */\n\n\n refreshXml_() {\n this.requestMain_((req, mainChanged) => {\n if (!mainChanged) {\n return;\n }\n\n if (this.media_) {\n this.media_ = this.mainPlaylistLoader_.main.playlists[this.media_.id];\n } // This will filter out updated sidx info from the mapping\n\n\n this.mainPlaylistLoader_.sidxMapping_ = filterChangedSidxMappings(this.mainPlaylistLoader_.main, this.mainPlaylistLoader_.sidxMapping_);\n this.addSidxSegments_(this.media(), this.state, sidxChanged => {\n // TODO: do we need to reload the current playlist?\n this.refreshMedia_(this.media().id);\n });\n });\n }\n /**\n * Refreshes the media playlist by re-parsing the main xml and updating playlist\n * references. If this is an alternate loader, the updated parsed manifest is retrieved\n * from the main loader.\n */\n\n\n refreshMedia_(mediaID) {\n if (!mediaID) {\n throw new Error('refreshMedia_ must take a media id');\n } // for main we have to reparse the main xml\n // to re-create segments based on current timing values\n // which may change media. We only skip updating the main manifest\n // if this is the first time this.media_ is being set.\n // as main was just parsed in that case.\n\n\n if (this.media_ && this.isMain_) {\n this.handleMain_();\n }\n\n const playlists = this.mainPlaylistLoader_.main.playlists;\n const mediaChanged = !this.media_ || this.media_ !== playlists[mediaID];\n\n if (mediaChanged) {\n this.media_ = playlists[mediaID];\n } else {\n this.trigger('playlistunchanged');\n }\n\n if (!this.mediaUpdateTimeout) {\n const createMediaUpdateTimeout = () => {\n if (this.media().endList) {\n return;\n }\n\n this.mediaUpdateTimeout = window$1.setTimeout(() => {\n this.trigger('mediaupdatetimeout');\n createMediaUpdateTimeout();\n }, refreshDelay(this.media(), Boolean(mediaChanged)));\n };\n\n createMediaUpdateTimeout();\n }\n\n this.trigger('loadedplaylist');\n }\n /**\n * Takes eventstream data from a parsed DASH manifest and adds it to the metadata text track.\n *\n * @param {manifest} newMain the newly parsed manifest\n */\n\n\n addEventStreamToMetadataTrack_(newMain) {\n // Only add new event stream metadata if we have a new manifest.\n if (newMain && this.mainPlaylistLoader_.main.eventStream) {\n // convert EventStream to ID3-like data.\n const metadataArray = this.mainPlaylistLoader_.main.eventStream.map(eventStreamNode => {\n return {\n cueTime: eventStreamNode.start,\n frames: [{\n data: eventStreamNode.messageData\n }]\n };\n });\n this.addMetadataToTextTrack('EventStream', metadataArray, this.mainPlaylistLoader_.main.duration);\n }\n }\n /**\n * Returns the key ID set from a playlist\n *\n * @param {playlist} playlist to fetch the key ID set from.\n * @return a Set of 32 digit hex strings that represent the unique keyIds for that playlist.\n */\n\n\n getKeyIdSet(playlist) {\n if (playlist.contentProtection) {\n const keyIds = new Set();\n\n for (const keysystem in playlist.contentProtection) {\n const defaultKID = playlist.contentProtection[keysystem].attributes['cenc:default_KID'];\n\n if (defaultKID) {\n // DASH keyIds are separated by dashes.\n keyIds.add(defaultKID.replace(/-/g, '').toLowerCase());\n }\n }\n\n return keyIds;\n }\n }\n\n}\n\nvar Config = {\n GOAL_BUFFER_LENGTH: 30,\n MAX_GOAL_BUFFER_LENGTH: 60,\n BACK_BUFFER_LENGTH: 30,\n GOAL_BUFFER_LENGTH_RATE: 1,\n // 0.5 MB/s\n INITIAL_BANDWIDTH: 4194304,\n // A fudge factor to apply to advertised playlist bitrates to account for\n // temporary flucations in client bandwidth\n BANDWIDTH_VARIANCE: 1.2,\n // How much of the buffer must be filled before we consider upswitching\n BUFFER_LOW_WATER_LINE: 0,\n MAX_BUFFER_LOW_WATER_LINE: 30,\n // TODO: Remove this when experimentalBufferBasedABR is removed\n EXPERIMENTAL_MAX_BUFFER_LOW_WATER_LINE: 16,\n BUFFER_LOW_WATER_LINE_RATE: 1,\n // If the buffer is greater than the high water line, we won't switch down\n BUFFER_HIGH_WATER_LINE: 30\n};\n\nconst stringToArrayBuffer = string => {\n const view = new Uint8Array(new ArrayBuffer(string.length));\n\n for (let i = 0; i < string.length; i++) {\n view[i] = string.charCodeAt(i);\n }\n\n return view.buffer;\n};\n\n/* global Blob, BlobBuilder, Worker */\n// unify worker interface\nconst browserWorkerPolyFill = function (workerObj) {\n // node only supports on/off\n workerObj.on = workerObj.addEventListener;\n workerObj.off = workerObj.removeEventListener;\n return workerObj;\n};\n\nconst createObjectURL = function (str) {\n try {\n return URL.createObjectURL(new Blob([str], {\n type: 'application/javascript'\n }));\n } catch (e) {\n const blob = new BlobBuilder();\n blob.append(str);\n return URL.createObjectURL(blob.getBlob());\n }\n};\n\nconst factory = function (code) {\n return function () {\n const objectUrl = createObjectURL(code);\n const worker = browserWorkerPolyFill(new Worker(objectUrl));\n worker.objURL = objectUrl;\n const terminate = worker.terminate;\n worker.on = worker.addEventListener;\n worker.off = worker.removeEventListener;\n\n worker.terminate = function () {\n URL.revokeObjectURL(objectUrl);\n return terminate.call(this);\n };\n\n return worker;\n };\n};\nconst transform = function (code) {\n return `var browserWorkerPolyFill = ${browserWorkerPolyFill.toString()};\\n` + 'browserWorkerPolyFill(self);\\n' + code;\n};\n\nconst getWorkerString = function (fn) {\n return fn.toString().replace(/^function.+?{/, '').slice(0, -1);\n};\n\n/* rollup-plugin-worker-factory start for worker!/home/runner/work/http-streaming/http-streaming/src/transmuxer-worker.js */\nconst workerCode$1 = transform(getWorkerString(function () {\n\n var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * A lightweight readable stream implemention that handles event dispatching.\n * Objects that inherit from streams should call init in their constructors.\n */\n\n var Stream$8 = function () {\n this.init = function () {\n var listeners = {};\n /**\n * Add a listener for a specified event type.\n * @param type {string} the event name\n * @param listener {function} the callback to be invoked when an event of\n * the specified type occurs\n */\n\n this.on = function (type, listener) {\n if (!listeners[type]) {\n listeners[type] = [];\n }\n\n listeners[type] = listeners[type].concat(listener);\n };\n /**\n * Remove a listener for a specified event type.\n * @param type {string} the event name\n * @param listener {function} a function previously registered for this\n * type of event through `on`\n */\n\n\n this.off = function (type, listener) {\n var index;\n\n if (!listeners[type]) {\n return false;\n }\n\n index = listeners[type].indexOf(listener);\n listeners[type] = listeners[type].slice();\n listeners[type].splice(index, 1);\n return index > -1;\n };\n /**\n * Trigger an event of the specified type on this stream. Any additional\n * arguments to this function are passed as parameters to event listeners.\n * @param type {string} the event name\n */\n\n\n this.trigger = function (type) {\n var callbacks, i, length, args;\n callbacks = listeners[type];\n\n if (!callbacks) {\n return;\n } // Slicing the arguments on every invocation of this method\n // can add a significant amount of overhead. Avoid the\n // intermediate object creation for the common case of a\n // single callback argument\n\n\n if (arguments.length === 2) {\n length = callbacks.length;\n\n for (i = 0; i < length; ++i) {\n callbacks[i].call(this, arguments[1]);\n }\n } else {\n args = [];\n i = arguments.length;\n\n for (i = 1; i < arguments.length; ++i) {\n args.push(arguments[i]);\n }\n\n length = callbacks.length;\n\n for (i = 0; i < length; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n };\n /**\n * Destroys the stream and cleans up.\n */\n\n\n this.dispose = function () {\n listeners = {};\n };\n };\n };\n /**\n * Forwards all `data` events on this stream to the destination stream. The\n * destination stream should provide a method `push` to receive the data\n * events as they arrive.\n * @param destination {stream} the stream that will receive all `data` events\n * @param autoFlush {boolean} if false, we will not call `flush` on the destination\n * when the current stream emits a 'done' event\n * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options\n */\n\n\n Stream$8.prototype.pipe = function (destination) {\n this.on('data', function (data) {\n destination.push(data);\n });\n this.on('done', function (flushSource) {\n destination.flush(flushSource);\n });\n this.on('partialdone', function (flushSource) {\n destination.partialFlush(flushSource);\n });\n this.on('endedtimeline', function (flushSource) {\n destination.endTimeline(flushSource);\n });\n this.on('reset', function (flushSource) {\n destination.reset(flushSource);\n });\n return destination;\n }; // Default stream functions that are expected to be overridden to perform\n // actual work. These are provided by the prototype as a sort of no-op\n // implementation so that we don't have to check for their existence in the\n // `pipe` function above.\n\n\n Stream$8.prototype.push = function (data) {\n this.trigger('data', data);\n };\n\n Stream$8.prototype.flush = function (flushSource) {\n this.trigger('done', flushSource);\n };\n\n Stream$8.prototype.partialFlush = function (flushSource) {\n this.trigger('partialdone', flushSource);\n };\n\n Stream$8.prototype.endTimeline = function (flushSource) {\n this.trigger('endedtimeline', flushSource);\n };\n\n Stream$8.prototype.reset = function (flushSource) {\n this.trigger('reset', flushSource);\n };\n\n var stream = Stream$8;\n var MAX_UINT32$1 = Math.pow(2, 32);\n\n var getUint64$5 = function (uint8) {\n var dv = new DataView(uint8.buffer, uint8.byteOffset, uint8.byteLength);\n var value;\n\n if (dv.getBigUint64) {\n value = dv.getBigUint64(0);\n\n if (value < Number.MAX_SAFE_INTEGER) {\n return Number(value);\n }\n\n return value;\n }\n\n return dv.getUint32(0) * MAX_UINT32$1 + dv.getUint32(4);\n };\n\n var numbers = {\n getUint64: getUint64$5,\n MAX_UINT32: MAX_UINT32$1\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Functions that generate fragmented MP4s suitable for use with Media\n * Source Extensions.\n */\n\n var MAX_UINT32 = numbers.MAX_UINT32;\n var box, dinf, esds, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak, tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, traf, trex, trun$1, types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR, AUDIO_HDLR, HDLR_TYPES, VMHD, SMHD, DREF, STCO, STSC, STSZ, STTS; // pre-calculate constants\n\n (function () {\n var i;\n types = {\n avc1: [],\n // codingname\n avcC: [],\n btrt: [],\n dinf: [],\n dref: [],\n esds: [],\n ftyp: [],\n hdlr: [],\n mdat: [],\n mdhd: [],\n mdia: [],\n mfhd: [],\n minf: [],\n moof: [],\n moov: [],\n mp4a: [],\n // codingname\n mvex: [],\n mvhd: [],\n pasp: [],\n sdtp: [],\n smhd: [],\n stbl: [],\n stco: [],\n stsc: [],\n stsd: [],\n stsz: [],\n stts: [],\n styp: [],\n tfdt: [],\n tfhd: [],\n traf: [],\n trak: [],\n trun: [],\n trex: [],\n tkhd: [],\n vmhd: []\n }; // In environments where Uint8Array is undefined (e.g., IE8), skip set up so that we\n // don't throw an error\n\n if (typeof Uint8Array === 'undefined') {\n return;\n }\n\n for (i in types) {\n if (types.hasOwnProperty(i)) {\n types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)];\n }\n }\n\n MAJOR_BRAND = new Uint8Array(['i'.charCodeAt(0), 's'.charCodeAt(0), 'o'.charCodeAt(0), 'm'.charCodeAt(0)]);\n AVC1_BRAND = new Uint8Array(['a'.charCodeAt(0), 'v'.charCodeAt(0), 'c'.charCodeAt(0), '1'.charCodeAt(0)]);\n MINOR_VERSION = new Uint8Array([0, 0, 0, 1]);\n VIDEO_HDLR = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x00, // pre_defined\n 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler'\n ]);\n AUDIO_HDLR = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x00, // pre_defined\n 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun'\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler'\n ]);\n HDLR_TYPES = {\n video: VIDEO_HDLR,\n audio: AUDIO_HDLR\n };\n DREF = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x01, // entry_count\n 0x00, 0x00, 0x00, 0x0c, // entry_size\n 0x75, 0x72, 0x6c, 0x20, // 'url' type\n 0x00, // version 0\n 0x00, 0x00, 0x01 // entry_flags\n ]);\n SMHD = new Uint8Array([0x00, // version\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, // balance, 0 means centered\n 0x00, 0x00 // reserved\n ]);\n STCO = new Uint8Array([0x00, // version\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x00 // entry_count\n ]);\n STSC = STCO;\n STSZ = new Uint8Array([0x00, // version\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x00, // sample_size\n 0x00, 0x00, 0x00, 0x00 // sample_count\n ]);\n STTS = STCO;\n VMHD = new Uint8Array([0x00, // version\n 0x00, 0x00, 0x01, // flags\n 0x00, 0x00, // graphicsmode\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor\n ]);\n })();\n\n box = function (type) {\n var payload = [],\n size = 0,\n i,\n result,\n view;\n\n for (i = 1; i < arguments.length; i++) {\n payload.push(arguments[i]);\n }\n\n i = payload.length; // calculate the total size we need to allocate\n\n while (i--) {\n size += payload[i].byteLength;\n }\n\n result = new Uint8Array(size + 8);\n view = new DataView(result.buffer, result.byteOffset, result.byteLength);\n view.setUint32(0, result.byteLength);\n result.set(type, 4); // copy the payload into the result\n\n for (i = 0, size = 8; i < payload.length; i++) {\n result.set(payload[i], size);\n size += payload[i].byteLength;\n }\n\n return result;\n };\n\n dinf = function () {\n return box(types.dinf, box(types.dref, DREF));\n };\n\n esds = function (track) {\n return box(types.esds, new Uint8Array([0x00, // version\n 0x00, 0x00, 0x00, // flags\n // ES_Descriptor\n 0x03, // tag, ES_DescrTag\n 0x19, // length\n 0x00, 0x00, // ES_ID\n 0x00, // streamDependenceFlag, URL_flag, reserved, streamPriority\n // DecoderConfigDescriptor\n 0x04, // tag, DecoderConfigDescrTag\n 0x11, // length\n 0x40, // object type\n 0x15, // streamType\n 0x00, 0x06, 0x00, // bufferSizeDB\n 0x00, 0x00, 0xda, 0xc0, // maxBitrate\n 0x00, 0x00, 0xda, 0xc0, // avgBitrate\n // DecoderSpecificInfo\n 0x05, // tag, DecoderSpecificInfoTag\n 0x02, // length\n // ISO/IEC 14496-3, AudioSpecificConfig\n // for samplingFrequencyIndex see ISO/IEC 13818-7:2006, 8.1.3.2.2, Table 35\n track.audioobjecttype << 3 | track.samplingfrequencyindex >>> 1, track.samplingfrequencyindex << 7 | track.channelcount << 3, 0x06, 0x01, 0x02 // GASpecificConfig\n ]));\n };\n\n ftyp = function () {\n return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND);\n };\n\n hdlr = function (type) {\n return box(types.hdlr, HDLR_TYPES[type]);\n };\n\n mdat = function (data) {\n return box(types.mdat, data);\n };\n\n mdhd = function (track) {\n var result = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x02, // creation_time\n 0x00, 0x00, 0x00, 0x03, // modification_time\n 0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 \"ticks\" per second\n track.duration >>> 24 & 0xFF, track.duration >>> 16 & 0xFF, track.duration >>> 8 & 0xFF, track.duration & 0xFF, // duration\n 0x55, 0xc4, // 'und' language (undetermined)\n 0x00, 0x00]); // Use the sample rate from the track metadata, when it is\n // defined. The sample rate can be parsed out of an ADTS header, for\n // instance.\n\n if (track.samplerate) {\n result[12] = track.samplerate >>> 24 & 0xFF;\n result[13] = track.samplerate >>> 16 & 0xFF;\n result[14] = track.samplerate >>> 8 & 0xFF;\n result[15] = track.samplerate & 0xFF;\n }\n\n return box(types.mdhd, result);\n };\n\n mdia = function (track) {\n return box(types.mdia, mdhd(track), hdlr(track.type), minf(track));\n };\n\n mfhd = function (sequenceNumber) {\n return box(types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // flags\n (sequenceNumber & 0xFF000000) >> 24, (sequenceNumber & 0xFF0000) >> 16, (sequenceNumber & 0xFF00) >> 8, sequenceNumber & 0xFF // sequence_number\n ]));\n };\n\n minf = function (track) {\n return box(types.minf, track.type === 'video' ? box(types.vmhd, VMHD) : box(types.smhd, SMHD), dinf(), stbl(track));\n };\n\n moof = function (sequenceNumber, tracks) {\n var trackFragments = [],\n i = tracks.length; // build traf boxes for each track fragment\n\n while (i--) {\n trackFragments[i] = traf(tracks[i]);\n }\n\n return box.apply(null, [types.moof, mfhd(sequenceNumber)].concat(trackFragments));\n };\n /**\n * Returns a movie box.\n * @param tracks {array} the tracks associated with this movie\n * @see ISO/IEC 14496-12:2012(E), section 8.2.1\n */\n\n\n moov = function (tracks) {\n var i = tracks.length,\n boxes = [];\n\n while (i--) {\n boxes[i] = trak(tracks[i]);\n }\n\n return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex(tracks)));\n };\n\n mvex = function (tracks) {\n var i = tracks.length,\n boxes = [];\n\n while (i--) {\n boxes[i] = trex(tracks[i]);\n }\n\n return box.apply(null, [types.mvex].concat(boxes));\n };\n\n mvhd = function (duration) {\n var bytes = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x01, // creation_time\n 0x00, 0x00, 0x00, 0x02, // modification_time\n 0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 \"ticks\" per second\n (duration & 0xFF000000) >> 24, (duration & 0xFF0000) >> 16, (duration & 0xFF00) >> 8, duration & 0xFF, // duration\n 0x00, 0x01, 0x00, 0x00, // 1.0 rate\n 0x01, 0x00, // 1.0 volume\n 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined\n 0xff, 0xff, 0xff, 0xff // next_track_ID\n ]);\n return box(types.mvhd, bytes);\n };\n\n sdtp = function (track) {\n var samples = track.samples || [],\n bytes = new Uint8Array(4 + samples.length),\n flags,\n i; // leave the full box header (4 bytes) all zero\n // write the sample table\n\n for (i = 0; i < samples.length; i++) {\n flags = samples[i].flags;\n bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy;\n }\n\n return box(types.sdtp, bytes);\n };\n\n stbl = function (track) {\n return box(types.stbl, stsd(track), box(types.stts, STTS), box(types.stsc, STSC), box(types.stsz, STSZ), box(types.stco, STCO));\n };\n\n (function () {\n var videoSample, audioSample;\n\n stsd = function (track) {\n return box(types.stsd, new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n 0x00, 0x00, 0x00, 0x01]), track.type === 'video' ? videoSample(track) : audioSample(track));\n };\n\n videoSample = function (track) {\n var sps = track.sps || [],\n pps = track.pps || [],\n sequenceParameterSets = [],\n pictureParameterSets = [],\n i,\n avc1Box; // assemble the SPSs\n\n for (i = 0; i < sps.length; i++) {\n sequenceParameterSets.push((sps[i].byteLength & 0xFF00) >>> 8);\n sequenceParameterSets.push(sps[i].byteLength & 0xFF); // sequenceParameterSetLength\n\n sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i])); // SPS\n } // assemble the PPSs\n\n\n for (i = 0; i < pps.length; i++) {\n pictureParameterSets.push((pps[i].byteLength & 0xFF00) >>> 8);\n pictureParameterSets.push(pps[i].byteLength & 0xFF);\n pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i]));\n }\n\n avc1Box = [types.avc1, new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x01, // data_reference_index\n 0x00, 0x00, // pre_defined\n 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined\n (track.width & 0xff00) >> 8, track.width & 0xff, // width\n (track.height & 0xff00) >> 8, track.height & 0xff, // height\n 0x00, 0x48, 0x00, 0x00, // horizresolution\n 0x00, 0x48, 0x00, 0x00, // vertresolution\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x01, // frame_count\n 0x13, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6a, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x2d, 0x68, 0x6c, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compressorname\n 0x00, 0x18, // depth = 24\n 0x11, 0x11 // pre_defined = -1\n ]), box(types.avcC, new Uint8Array([0x01, // configurationVersion\n track.profileIdc, // AVCProfileIndication\n track.profileCompatibility, // profile_compatibility\n track.levelIdc, // AVCLevelIndication\n 0xff // lengthSizeMinusOne, hard-coded to 4 bytes\n ].concat([sps.length], // numOfSequenceParameterSets\n sequenceParameterSets, // \"SPS\"\n [pps.length], // numOfPictureParameterSets\n pictureParameterSets // \"PPS\"\n ))), box(types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB\n 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate\n 0x00, 0x2d, 0xc6, 0xc0 // avgBitrate\n ]))];\n\n if (track.sarRatio) {\n var hSpacing = track.sarRatio[0],\n vSpacing = track.sarRatio[1];\n avc1Box.push(box(types.pasp, new Uint8Array([(hSpacing & 0xFF000000) >> 24, (hSpacing & 0xFF0000) >> 16, (hSpacing & 0xFF00) >> 8, hSpacing & 0xFF, (vSpacing & 0xFF000000) >> 24, (vSpacing & 0xFF0000) >> 16, (vSpacing & 0xFF00) >> 8, vSpacing & 0xFF])));\n }\n\n return box.apply(null, avc1Box);\n };\n\n audioSample = function (track) {\n return box(types.mp4a, new Uint8Array([// SampleEntry, ISO/IEC 14496-12\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x01, // data_reference_index\n // AudioSampleEntry, ISO/IEC 14496-12\n 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, 0x00, 0x00, // reserved\n (track.channelcount & 0xff00) >> 8, track.channelcount & 0xff, // channelcount\n (track.samplesize & 0xff00) >> 8, track.samplesize & 0xff, // samplesize\n 0x00, 0x00, // pre_defined\n 0x00, 0x00, // reserved\n (track.samplerate & 0xff00) >> 8, track.samplerate & 0xff, 0x00, 0x00 // samplerate, 16.16\n // MP4AudioSampleEntry, ISO/IEC 14496-14\n ]), esds(track));\n };\n })();\n\n tkhd = function (track) {\n var result = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x07, // flags\n 0x00, 0x00, 0x00, 0x00, // creation_time\n 0x00, 0x00, 0x00, 0x00, // modification_time\n (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID\n 0x00, 0x00, 0x00, 0x00, // reserved\n (track.duration & 0xFF000000) >> 24, (track.duration & 0xFF0000) >> 16, (track.duration & 0xFF00) >> 8, track.duration & 0xFF, // duration\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n 0x00, 0x00, // layer\n 0x00, 0x00, // alternate_group\n 0x01, 0x00, // non-audio track volume\n 0x00, 0x00, // reserved\n 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix\n (track.width & 0xFF00) >> 8, track.width & 0xFF, 0x00, 0x00, // width\n (track.height & 0xFF00) >> 8, track.height & 0xFF, 0x00, 0x00 // height\n ]);\n return box(types.tkhd, result);\n };\n /**\n * Generate a track fragment (traf) box. A traf box collects metadata\n * about tracks in a movie fragment (moof) box.\n */\n\n\n traf = function (track) {\n var trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable, dataOffset, upperWordBaseMediaDecodeTime, lowerWordBaseMediaDecodeTime;\n trackFragmentHeader = box(types.tfhd, new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x3a, // flags\n (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID\n 0x00, 0x00, 0x00, 0x01, // sample_description_index\n 0x00, 0x00, 0x00, 0x00, // default_sample_duration\n 0x00, 0x00, 0x00, 0x00, // default_sample_size\n 0x00, 0x00, 0x00, 0x00 // default_sample_flags\n ]));\n upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / MAX_UINT32);\n lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % MAX_UINT32);\n trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([0x01, // version 1\n 0x00, 0x00, 0x00, // flags\n // baseMediaDecodeTime\n upperWordBaseMediaDecodeTime >>> 24 & 0xFF, upperWordBaseMediaDecodeTime >>> 16 & 0xFF, upperWordBaseMediaDecodeTime >>> 8 & 0xFF, upperWordBaseMediaDecodeTime & 0xFF, lowerWordBaseMediaDecodeTime >>> 24 & 0xFF, lowerWordBaseMediaDecodeTime >>> 16 & 0xFF, lowerWordBaseMediaDecodeTime >>> 8 & 0xFF, lowerWordBaseMediaDecodeTime & 0xFF])); // the data offset specifies the number of bytes from the start of\n // the containing moof to the first payload byte of the associated\n // mdat\n\n dataOffset = 32 + // tfhd\n 20 + // tfdt\n 8 + // traf header\n 16 + // mfhd\n 8 + // moof header\n 8; // mdat header\n // audio tracks require less metadata\n\n if (track.type === 'audio') {\n trackFragmentRun = trun$1(track, dataOffset);\n return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun);\n } // video tracks should contain an independent and disposable samples\n // box (sdtp)\n // generate one and adjust offsets to match\n\n\n sampleDependencyTable = sdtp(track);\n trackFragmentRun = trun$1(track, sampleDependencyTable.length + dataOffset);\n return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable);\n };\n /**\n * Generate a track box.\n * @param track {object} a track definition\n * @return {Uint8Array} the track box\n */\n\n\n trak = function (track) {\n track.duration = track.duration || 0xffffffff;\n return box(types.trak, tkhd(track), mdia(track));\n };\n\n trex = function (track) {\n var result = new Uint8Array([0x00, // version 0\n 0x00, 0x00, 0x00, // flags\n (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID\n 0x00, 0x00, 0x00, 0x01, // default_sample_description_index\n 0x00, 0x00, 0x00, 0x00, // default_sample_duration\n 0x00, 0x00, 0x00, 0x00, // default_sample_size\n 0x00, 0x01, 0x00, 0x01 // default_sample_flags\n ]); // the last two bytes of default_sample_flags is the sample\n // degradation priority, a hint about the importance of this sample\n // relative to others. Lower the degradation priority for all sample\n // types other than video.\n\n if (track.type !== 'video') {\n result[result.length - 1] = 0x00;\n }\n\n return box(types.trex, result);\n };\n\n (function () {\n var audioTrun, videoTrun, trunHeader; // This method assumes all samples are uniform. That is, if a\n // duration is present for the first sample, it will be present for\n // all subsequent samples.\n // see ISO/IEC 14496-12:2012, Section 8.8.8.1\n\n trunHeader = function (samples, offset) {\n var durationPresent = 0,\n sizePresent = 0,\n flagsPresent = 0,\n compositionTimeOffset = 0; // trun flag constants\n\n if (samples.length) {\n if (samples[0].duration !== undefined) {\n durationPresent = 0x1;\n }\n\n if (samples[0].size !== undefined) {\n sizePresent = 0x2;\n }\n\n if (samples[0].flags !== undefined) {\n flagsPresent = 0x4;\n }\n\n if (samples[0].compositionTimeOffset !== undefined) {\n compositionTimeOffset = 0x8;\n }\n }\n\n return [0x00, // version 0\n 0x00, durationPresent | sizePresent | flagsPresent | compositionTimeOffset, 0x01, // flags\n (samples.length & 0xFF000000) >>> 24, (samples.length & 0xFF0000) >>> 16, (samples.length & 0xFF00) >>> 8, samples.length & 0xFF, // sample_count\n (offset & 0xFF000000) >>> 24, (offset & 0xFF0000) >>> 16, (offset & 0xFF00) >>> 8, offset & 0xFF // data_offset\n ];\n };\n\n videoTrun = function (track, offset) {\n var bytesOffest, bytes, header, samples, sample, i;\n samples = track.samples || [];\n offset += 8 + 12 + 16 * samples.length;\n header = trunHeader(samples, offset);\n bytes = new Uint8Array(header.length + samples.length * 16);\n bytes.set(header);\n bytesOffest = header.length;\n\n for (i = 0; i < samples.length; i++) {\n sample = samples[i];\n bytes[bytesOffest++] = (sample.duration & 0xFF000000) >>> 24;\n bytes[bytesOffest++] = (sample.duration & 0xFF0000) >>> 16;\n bytes[bytesOffest++] = (sample.duration & 0xFF00) >>> 8;\n bytes[bytesOffest++] = sample.duration & 0xFF; // sample_duration\n\n bytes[bytesOffest++] = (sample.size & 0xFF000000) >>> 24;\n bytes[bytesOffest++] = (sample.size & 0xFF0000) >>> 16;\n bytes[bytesOffest++] = (sample.size & 0xFF00) >>> 8;\n bytes[bytesOffest++] = sample.size & 0xFF; // sample_size\n\n bytes[bytesOffest++] = sample.flags.isLeading << 2 | sample.flags.dependsOn;\n bytes[bytesOffest++] = sample.flags.isDependedOn << 6 | sample.flags.hasRedundancy << 4 | sample.flags.paddingValue << 1 | sample.flags.isNonSyncSample;\n bytes[bytesOffest++] = sample.flags.degradationPriority & 0xF0 << 8;\n bytes[bytesOffest++] = sample.flags.degradationPriority & 0x0F; // sample_flags\n\n bytes[bytesOffest++] = (sample.compositionTimeOffset & 0xFF000000) >>> 24;\n bytes[bytesOffest++] = (sample.compositionTimeOffset & 0xFF0000) >>> 16;\n bytes[bytesOffest++] = (sample.compositionTimeOffset & 0xFF00) >>> 8;\n bytes[bytesOffest++] = sample.compositionTimeOffset & 0xFF; // sample_composition_time_offset\n }\n\n return box(types.trun, bytes);\n };\n\n audioTrun = function (track, offset) {\n var bytes, bytesOffest, header, samples, sample, i;\n samples = track.samples || [];\n offset += 8 + 12 + 8 * samples.length;\n header = trunHeader(samples, offset);\n bytes = new Uint8Array(header.length + samples.length * 8);\n bytes.set(header);\n bytesOffest = header.length;\n\n for (i = 0; i < samples.length; i++) {\n sample = samples[i];\n bytes[bytesOffest++] = (sample.duration & 0xFF000000) >>> 24;\n bytes[bytesOffest++] = (sample.duration & 0xFF0000) >>> 16;\n bytes[bytesOffest++] = (sample.duration & 0xFF00) >>> 8;\n bytes[bytesOffest++] = sample.duration & 0xFF; // sample_duration\n\n bytes[bytesOffest++] = (sample.size & 0xFF000000) >>> 24;\n bytes[bytesOffest++] = (sample.size & 0xFF0000) >>> 16;\n bytes[bytesOffest++] = (sample.size & 0xFF00) >>> 8;\n bytes[bytesOffest++] = sample.size & 0xFF; // sample_size\n }\n\n return box(types.trun, bytes);\n };\n\n trun$1 = function (track, offset) {\n if (track.type === 'audio') {\n return audioTrun(track, offset);\n }\n\n return videoTrun(track, offset);\n };\n })();\n\n var mp4Generator = {\n ftyp: ftyp,\n mdat: mdat,\n moof: moof,\n moov: moov,\n initSegment: function (tracks) {\n var fileType = ftyp(),\n movie = moov(tracks),\n result;\n result = new Uint8Array(fileType.byteLength + movie.byteLength);\n result.set(fileType);\n result.set(movie, fileType.byteLength);\n return result;\n }\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n // composed of the nal units that make up that frame\n // Also keep track of cummulative data about the frame from the nal units such\n // as the frame duration, starting pts, etc.\n\n var groupNalsIntoFrames = function (nalUnits) {\n var i,\n currentNal,\n currentFrame = [],\n frames = []; // TODO added for LHLS, make sure this is OK\n\n frames.byteLength = 0;\n frames.nalCount = 0;\n frames.duration = 0;\n currentFrame.byteLength = 0;\n\n for (i = 0; i < nalUnits.length; i++) {\n currentNal = nalUnits[i]; // Split on 'aud'-type nal units\n\n if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') {\n // Since the very first nal unit is expected to be an AUD\n // only push to the frames array when currentFrame is not empty\n if (currentFrame.length) {\n currentFrame.duration = currentNal.dts - currentFrame.dts; // TODO added for LHLS, make sure this is OK\n\n frames.byteLength += currentFrame.byteLength;\n frames.nalCount += currentFrame.length;\n frames.duration += currentFrame.duration;\n frames.push(currentFrame);\n }\n\n currentFrame = [currentNal];\n currentFrame.byteLength = currentNal.data.byteLength;\n currentFrame.pts = currentNal.pts;\n currentFrame.dts = currentNal.dts;\n } else {\n // Specifically flag key frames for ease of use later\n if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') {\n currentFrame.keyFrame = true;\n }\n\n currentFrame.duration = currentNal.dts - currentFrame.dts;\n currentFrame.byteLength += currentNal.data.byteLength;\n currentFrame.push(currentNal);\n }\n } // For the last frame, use the duration of the previous frame if we\n // have nothing better to go on\n\n\n if (frames.length && (!currentFrame.duration || currentFrame.duration <= 0)) {\n currentFrame.duration = frames[frames.length - 1].duration;\n } // Push the final frame\n // TODO added for LHLS, make sure this is OK\n\n\n frames.byteLength += currentFrame.byteLength;\n frames.nalCount += currentFrame.length;\n frames.duration += currentFrame.duration;\n frames.push(currentFrame);\n return frames;\n }; // Convert an array of frames into an array of Gop with each Gop being composed\n // of the frames that make up that Gop\n // Also keep track of cummulative data about the Gop from the frames such as the\n // Gop duration, starting pts, etc.\n\n\n var groupFramesIntoGops = function (frames) {\n var i,\n currentFrame,\n currentGop = [],\n gops = []; // We must pre-set some of the values on the Gop since we\n // keep running totals of these values\n\n currentGop.byteLength = 0;\n currentGop.nalCount = 0;\n currentGop.duration = 0;\n currentGop.pts = frames[0].pts;\n currentGop.dts = frames[0].dts; // store some metadata about all the Gops\n\n gops.byteLength = 0;\n gops.nalCount = 0;\n gops.duration = 0;\n gops.pts = frames[0].pts;\n gops.dts = frames[0].dts;\n\n for (i = 0; i < frames.length; i++) {\n currentFrame = frames[i];\n\n if (currentFrame.keyFrame) {\n // Since the very first frame is expected to be an keyframe\n // only push to the gops array when currentGop is not empty\n if (currentGop.length) {\n gops.push(currentGop);\n gops.byteLength += currentGop.byteLength;\n gops.nalCount += currentGop.nalCount;\n gops.duration += currentGop.duration;\n }\n\n currentGop = [currentFrame];\n currentGop.nalCount = currentFrame.length;\n currentGop.byteLength = currentFrame.byteLength;\n currentGop.pts = currentFrame.pts;\n currentGop.dts = currentFrame.dts;\n currentGop.duration = currentFrame.duration;\n } else {\n currentGop.duration += currentFrame.duration;\n currentGop.nalCount += currentFrame.length;\n currentGop.byteLength += currentFrame.byteLength;\n currentGop.push(currentFrame);\n }\n }\n\n if (gops.length && currentGop.duration <= 0) {\n currentGop.duration = gops[gops.length - 1].duration;\n }\n\n gops.byteLength += currentGop.byteLength;\n gops.nalCount += currentGop.nalCount;\n gops.duration += currentGop.duration; // push the final Gop\n\n gops.push(currentGop);\n return gops;\n };\n /*\n * Search for the first keyframe in the GOPs and throw away all frames\n * until that keyframe. Then extend the duration of the pulled keyframe\n * and pull the PTS and DTS of the keyframe so that it covers the time\n * range of the frames that were disposed.\n *\n * @param {Array} gops video GOPs\n * @returns {Array} modified video GOPs\n */\n\n\n var extendFirstKeyFrame = function (gops) {\n var currentGop;\n\n if (!gops[0][0].keyFrame && gops.length > 1) {\n // Remove the first GOP\n currentGop = gops.shift();\n gops.byteLength -= currentGop.byteLength;\n gops.nalCount -= currentGop.nalCount; // Extend the first frame of what is now the\n // first gop to cover the time period of the\n // frames we just removed\n\n gops[0][0].dts = currentGop.dts;\n gops[0][0].pts = currentGop.pts;\n gops[0][0].duration += currentGop.duration;\n }\n\n return gops;\n };\n /**\n * Default sample object\n * see ISO/IEC 14496-12:2012, section 8.6.4.3\n */\n\n\n var createDefaultSample = function () {\n return {\n size: 0,\n flags: {\n isLeading: 0,\n dependsOn: 1,\n isDependedOn: 0,\n hasRedundancy: 0,\n degradationPriority: 0,\n isNonSyncSample: 1\n }\n };\n };\n /*\n * Collates information from a video frame into an object for eventual\n * entry into an MP4 sample table.\n *\n * @param {Object} frame the video frame\n * @param {Number} dataOffset the byte offset to position the sample\n * @return {Object} object containing sample table info for a frame\n */\n\n\n var sampleForFrame = function (frame, dataOffset) {\n var sample = createDefaultSample();\n sample.dataOffset = dataOffset;\n sample.compositionTimeOffset = frame.pts - frame.dts;\n sample.duration = frame.duration;\n sample.size = 4 * frame.length; // Space for nal unit size\n\n sample.size += frame.byteLength;\n\n if (frame.keyFrame) {\n sample.flags.dependsOn = 2;\n sample.flags.isNonSyncSample = 0;\n }\n\n return sample;\n }; // generate the track's sample table from an array of gops\n\n\n var generateSampleTable$1 = function (gops, baseDataOffset) {\n var h,\n i,\n sample,\n currentGop,\n currentFrame,\n dataOffset = baseDataOffset || 0,\n samples = [];\n\n for (h = 0; h < gops.length; h++) {\n currentGop = gops[h];\n\n for (i = 0; i < currentGop.length; i++) {\n currentFrame = currentGop[i];\n sample = sampleForFrame(currentFrame, dataOffset);\n dataOffset += sample.size;\n samples.push(sample);\n }\n }\n\n return samples;\n }; // generate the track's raw mdat data from an array of gops\n\n\n var concatenateNalData = function (gops) {\n var h,\n i,\n j,\n currentGop,\n currentFrame,\n currentNal,\n dataOffset = 0,\n nalsByteLength = gops.byteLength,\n numberOfNals = gops.nalCount,\n totalByteLength = nalsByteLength + 4 * numberOfNals,\n data = new Uint8Array(totalByteLength),\n view = new DataView(data.buffer); // For each Gop..\n\n for (h = 0; h < gops.length; h++) {\n currentGop = gops[h]; // For each Frame..\n\n for (i = 0; i < currentGop.length; i++) {\n currentFrame = currentGop[i]; // For each NAL..\n\n for (j = 0; j < currentFrame.length; j++) {\n currentNal = currentFrame[j];\n view.setUint32(dataOffset, currentNal.data.byteLength);\n dataOffset += 4;\n data.set(currentNal.data, dataOffset);\n dataOffset += currentNal.data.byteLength;\n }\n }\n }\n\n return data;\n }; // generate the track's sample table from a frame\n\n\n var generateSampleTableForFrame = function (frame, baseDataOffset) {\n var sample,\n dataOffset = baseDataOffset || 0,\n samples = [];\n sample = sampleForFrame(frame, dataOffset);\n samples.push(sample);\n return samples;\n }; // generate the track's raw mdat data from a frame\n\n\n var concatenateNalDataForFrame = function (frame) {\n var i,\n currentNal,\n dataOffset = 0,\n nalsByteLength = frame.byteLength,\n numberOfNals = frame.length,\n totalByteLength = nalsByteLength + 4 * numberOfNals,\n data = new Uint8Array(totalByteLength),\n view = new DataView(data.buffer); // For each NAL..\n\n for (i = 0; i < frame.length; i++) {\n currentNal = frame[i];\n view.setUint32(dataOffset, currentNal.data.byteLength);\n dataOffset += 4;\n data.set(currentNal.data, dataOffset);\n dataOffset += currentNal.data.byteLength;\n }\n\n return data;\n };\n\n var frameUtils$1 = {\n groupNalsIntoFrames: groupNalsIntoFrames,\n groupFramesIntoGops: groupFramesIntoGops,\n extendFirstKeyFrame: extendFirstKeyFrame,\n generateSampleTable: generateSampleTable$1,\n concatenateNalData: concatenateNalData,\n generateSampleTableForFrame: generateSampleTableForFrame,\n concatenateNalDataForFrame: concatenateNalDataForFrame\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var highPrefix = [33, 16, 5, 32, 164, 27];\n var lowPrefix = [33, 65, 108, 84, 1, 2, 4, 8, 168, 2, 4, 8, 17, 191, 252];\n\n var zeroFill = function (count) {\n var a = [];\n\n while (count--) {\n a.push(0);\n }\n\n return a;\n };\n\n var makeTable = function (metaTable) {\n return Object.keys(metaTable).reduce(function (obj, key) {\n obj[key] = new Uint8Array(metaTable[key].reduce(function (arr, part) {\n return arr.concat(part);\n }, []));\n return obj;\n }, {});\n };\n\n var silence;\n\n var silence_1 = function () {\n if (!silence) {\n // Frames-of-silence to use for filling in missing AAC frames\n var coneOfSilence = {\n 96000: [highPrefix, [227, 64], zeroFill(154), [56]],\n 88200: [highPrefix, [231], zeroFill(170), [56]],\n 64000: [highPrefix, [248, 192], zeroFill(240), [56]],\n 48000: [highPrefix, [255, 192], zeroFill(268), [55, 148, 128], zeroFill(54), [112]],\n 44100: [highPrefix, [255, 192], zeroFill(268), [55, 163, 128], zeroFill(84), [112]],\n 32000: [highPrefix, [255, 192], zeroFill(268), [55, 234], zeroFill(226), [112]],\n 24000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 112], zeroFill(126), [224]],\n 16000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 255], zeroFill(269), [223, 108], zeroFill(195), [1, 192]],\n 12000: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 253, 128], zeroFill(259), [56]],\n 11025: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 255, 192], zeroFill(268), [55, 175, 128], zeroFill(108), [112]],\n 8000: [lowPrefix, zeroFill(268), [3, 121, 16], zeroFill(47), [7]]\n };\n silence = makeTable(coneOfSilence);\n }\n\n return silence;\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n\n var ONE_SECOND_IN_TS$4 = 90000,\n // 90kHz clock\n secondsToVideoTs,\n secondsToAudioTs,\n videoTsToSeconds,\n audioTsToSeconds,\n audioTsToVideoTs,\n videoTsToAudioTs,\n metadataTsToSeconds;\n\n secondsToVideoTs = function (seconds) {\n return seconds * ONE_SECOND_IN_TS$4;\n };\n\n secondsToAudioTs = function (seconds, sampleRate) {\n return seconds * sampleRate;\n };\n\n videoTsToSeconds = function (timestamp) {\n return timestamp / ONE_SECOND_IN_TS$4;\n };\n\n audioTsToSeconds = function (timestamp, sampleRate) {\n return timestamp / sampleRate;\n };\n\n audioTsToVideoTs = function (timestamp, sampleRate) {\n return secondsToVideoTs(audioTsToSeconds(timestamp, sampleRate));\n };\n\n videoTsToAudioTs = function (timestamp, sampleRate) {\n return secondsToAudioTs(videoTsToSeconds(timestamp), sampleRate);\n };\n /**\n * Adjust ID3 tag or caption timing information by the timeline pts values\n * (if keepOriginalTimestamps is false) and convert to seconds\n */\n\n\n metadataTsToSeconds = function (timestamp, timelineStartPts, keepOriginalTimestamps) {\n return videoTsToSeconds(keepOriginalTimestamps ? timestamp : timestamp - timelineStartPts);\n };\n\n var clock$2 = {\n ONE_SECOND_IN_TS: ONE_SECOND_IN_TS$4,\n secondsToVideoTs: secondsToVideoTs,\n secondsToAudioTs: secondsToAudioTs,\n videoTsToSeconds: videoTsToSeconds,\n audioTsToSeconds: audioTsToSeconds,\n audioTsToVideoTs: audioTsToVideoTs,\n videoTsToAudioTs: videoTsToAudioTs,\n metadataTsToSeconds: metadataTsToSeconds\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var coneOfSilence = silence_1;\n var clock$1 = clock$2;\n /**\n * Sum the `byteLength` properties of the data in each AAC frame\n */\n\n var sumFrameByteLengths = function (array) {\n var i,\n currentObj,\n sum = 0; // sum the byteLength's all each nal unit in the frame\n\n for (i = 0; i < array.length; i++) {\n currentObj = array[i];\n sum += currentObj.data.byteLength;\n }\n\n return sum;\n }; // Possibly pad (prefix) the audio track with silence if appending this track\n // would lead to the introduction of a gap in the audio buffer\n\n\n var prefixWithSilence = function (track, frames, audioAppendStartTs, videoBaseMediaDecodeTime) {\n var baseMediaDecodeTimeTs,\n frameDuration = 0,\n audioGapDuration = 0,\n audioFillFrameCount = 0,\n audioFillDuration = 0,\n silentFrame,\n i,\n firstFrame;\n\n if (!frames.length) {\n return;\n }\n\n baseMediaDecodeTimeTs = clock$1.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate); // determine frame clock duration based on sample rate, round up to avoid overfills\n\n frameDuration = Math.ceil(clock$1.ONE_SECOND_IN_TS / (track.samplerate / 1024));\n\n if (audioAppendStartTs && videoBaseMediaDecodeTime) {\n // insert the shortest possible amount (audio gap or audio to video gap)\n audioGapDuration = baseMediaDecodeTimeTs - Math.max(audioAppendStartTs, videoBaseMediaDecodeTime); // number of full frames in the audio gap\n\n audioFillFrameCount = Math.floor(audioGapDuration / frameDuration);\n audioFillDuration = audioFillFrameCount * frameDuration;\n } // don't attempt to fill gaps smaller than a single frame or larger\n // than a half second\n\n\n if (audioFillFrameCount < 1 || audioFillDuration > clock$1.ONE_SECOND_IN_TS / 2) {\n return;\n }\n\n silentFrame = coneOfSilence()[track.samplerate];\n\n if (!silentFrame) {\n // we don't have a silent frame pregenerated for the sample rate, so use a frame\n // from the content instead\n silentFrame = frames[0].data;\n }\n\n for (i = 0; i < audioFillFrameCount; i++) {\n firstFrame = frames[0];\n frames.splice(0, 0, {\n data: silentFrame,\n dts: firstFrame.dts - frameDuration,\n pts: firstFrame.pts - frameDuration\n });\n }\n\n track.baseMediaDecodeTime -= Math.floor(clock$1.videoTsToAudioTs(audioFillDuration, track.samplerate));\n return audioFillDuration;\n }; // If the audio segment extends before the earliest allowed dts\n // value, remove AAC frames until starts at or after the earliest\n // allowed DTS so that we don't end up with a negative baseMedia-\n // DecodeTime for the audio track\n\n\n var trimAdtsFramesByEarliestDts = function (adtsFrames, track, earliestAllowedDts) {\n if (track.minSegmentDts >= earliestAllowedDts) {\n return adtsFrames;\n } // We will need to recalculate the earliest segment Dts\n\n\n track.minSegmentDts = Infinity;\n return adtsFrames.filter(function (currentFrame) {\n // If this is an allowed frame, keep it and record it's Dts\n if (currentFrame.dts >= earliestAllowedDts) {\n track.minSegmentDts = Math.min(track.minSegmentDts, currentFrame.dts);\n track.minSegmentPts = track.minSegmentDts;\n return true;\n } // Otherwise, discard it\n\n\n return false;\n });\n }; // generate the track's raw mdat data from an array of frames\n\n\n var generateSampleTable = function (frames) {\n var i,\n currentFrame,\n samples = [];\n\n for (i = 0; i < frames.length; i++) {\n currentFrame = frames[i];\n samples.push({\n size: currentFrame.data.byteLength,\n duration: 1024 // For AAC audio, all samples contain 1024 samples\n\n });\n }\n\n return samples;\n }; // generate the track's sample table from an array of frames\n\n\n var concatenateFrameData = function (frames) {\n var i,\n currentFrame,\n dataOffset = 0,\n data = new Uint8Array(sumFrameByteLengths(frames));\n\n for (i = 0; i < frames.length; i++) {\n currentFrame = frames[i];\n data.set(currentFrame.data, dataOffset);\n dataOffset += currentFrame.data.byteLength;\n }\n\n return data;\n };\n\n var audioFrameUtils$1 = {\n prefixWithSilence: prefixWithSilence,\n trimAdtsFramesByEarliestDts: trimAdtsFramesByEarliestDts,\n generateSampleTable: generateSampleTable,\n concatenateFrameData: concatenateFrameData\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var ONE_SECOND_IN_TS$3 = clock$2.ONE_SECOND_IN_TS;\n /**\n * Store information about the start and end of the track and the\n * duration for each frame/sample we process in order to calculate\n * the baseMediaDecodeTime\n */\n\n var collectDtsInfo = function (track, data) {\n if (typeof data.pts === 'number') {\n if (track.timelineStartInfo.pts === undefined) {\n track.timelineStartInfo.pts = data.pts;\n }\n\n if (track.minSegmentPts === undefined) {\n track.minSegmentPts = data.pts;\n } else {\n track.minSegmentPts = Math.min(track.minSegmentPts, data.pts);\n }\n\n if (track.maxSegmentPts === undefined) {\n track.maxSegmentPts = data.pts;\n } else {\n track.maxSegmentPts = Math.max(track.maxSegmentPts, data.pts);\n }\n }\n\n if (typeof data.dts === 'number') {\n if (track.timelineStartInfo.dts === undefined) {\n track.timelineStartInfo.dts = data.dts;\n }\n\n if (track.minSegmentDts === undefined) {\n track.minSegmentDts = data.dts;\n } else {\n track.minSegmentDts = Math.min(track.minSegmentDts, data.dts);\n }\n\n if (track.maxSegmentDts === undefined) {\n track.maxSegmentDts = data.dts;\n } else {\n track.maxSegmentDts = Math.max(track.maxSegmentDts, data.dts);\n }\n }\n };\n /**\n * Clear values used to calculate the baseMediaDecodeTime between\n * tracks\n */\n\n\n var clearDtsInfo = function (track) {\n delete track.minSegmentDts;\n delete track.maxSegmentDts;\n delete track.minSegmentPts;\n delete track.maxSegmentPts;\n };\n /**\n * Calculate the track's baseMediaDecodeTime based on the earliest\n * DTS the transmuxer has ever seen and the minimum DTS for the\n * current track\n * @param track {object} track metadata configuration\n * @param keepOriginalTimestamps {boolean} If true, keep the timestamps\n * in the source; false to adjust the first segment to start at 0.\n */\n\n\n var calculateTrackBaseMediaDecodeTime = function (track, keepOriginalTimestamps) {\n var baseMediaDecodeTime,\n scale,\n minSegmentDts = track.minSegmentDts; // Optionally adjust the time so the first segment starts at zero.\n\n if (!keepOriginalTimestamps) {\n minSegmentDts -= track.timelineStartInfo.dts;\n } // track.timelineStartInfo.baseMediaDecodeTime is the location, in time, where\n // we want the start of the first segment to be placed\n\n\n baseMediaDecodeTime = track.timelineStartInfo.baseMediaDecodeTime; // Add to that the distance this segment is from the very first\n\n baseMediaDecodeTime += minSegmentDts; // baseMediaDecodeTime must not become negative\n\n baseMediaDecodeTime = Math.max(0, baseMediaDecodeTime);\n\n if (track.type === 'audio') {\n // Audio has a different clock equal to the sampling_rate so we need to\n // scale the PTS values into the clock rate of the track\n scale = track.samplerate / ONE_SECOND_IN_TS$3;\n baseMediaDecodeTime *= scale;\n baseMediaDecodeTime = Math.floor(baseMediaDecodeTime);\n }\n\n return baseMediaDecodeTime;\n };\n\n var trackDecodeInfo$1 = {\n clearDtsInfo: clearDtsInfo,\n calculateTrackBaseMediaDecodeTime: calculateTrackBaseMediaDecodeTime,\n collectDtsInfo: collectDtsInfo\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Reads in-band caption information from a video elementary\n * stream. Captions must follow the CEA-708 standard for injection\n * into an MPEG-2 transport streams.\n * @see https://en.wikipedia.org/wiki/CEA-708\n * @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf\n */\n // payload type field to indicate how they are to be\n // interpreted. CEAS-708 caption content is always transmitted with\n // payload type 0x04.\n\n var USER_DATA_REGISTERED_ITU_T_T35 = 4,\n RBSP_TRAILING_BITS = 128;\n /**\n * Parse a supplemental enhancement information (SEI) NAL unit.\n * Stops parsing once a message of type ITU T T35 has been found.\n *\n * @param bytes {Uint8Array} the bytes of a SEI NAL unit\n * @return {object} the parsed SEI payload\n * @see Rec. ITU-T H.264, 7.3.2.3.1\n */\n\n var parseSei = function (bytes) {\n var i = 0,\n result = {\n payloadType: -1,\n payloadSize: 0\n },\n payloadType = 0,\n payloadSize = 0; // go through the sei_rbsp parsing each each individual sei_message\n\n while (i < bytes.byteLength) {\n // stop once we have hit the end of the sei_rbsp\n if (bytes[i] === RBSP_TRAILING_BITS) {\n break;\n } // Parse payload type\n\n\n while (bytes[i] === 0xFF) {\n payloadType += 255;\n i++;\n }\n\n payloadType += bytes[i++]; // Parse payload size\n\n while (bytes[i] === 0xFF) {\n payloadSize += 255;\n i++;\n }\n\n payloadSize += bytes[i++]; // this sei_message is a 608/708 caption so save it and break\n // there can only ever be one caption message in a frame's sei\n\n if (!result.payload && payloadType === USER_DATA_REGISTERED_ITU_T_T35) {\n var userIdentifier = String.fromCharCode(bytes[i + 3], bytes[i + 4], bytes[i + 5], bytes[i + 6]);\n\n if (userIdentifier === 'GA94') {\n result.payloadType = payloadType;\n result.payloadSize = payloadSize;\n result.payload = bytes.subarray(i, i + payloadSize);\n break;\n } else {\n result.payload = void 0;\n }\n } // skip the payload and parse the next message\n\n\n i += payloadSize;\n payloadType = 0;\n payloadSize = 0;\n }\n\n return result;\n }; // see ANSI/SCTE 128-1 (2013), section 8.1\n\n\n var parseUserData = function (sei) {\n // itu_t_t35_contry_code must be 181 (United States) for\n // captions\n if (sei.payload[0] !== 181) {\n return null;\n } // itu_t_t35_provider_code should be 49 (ATSC) for captions\n\n\n if ((sei.payload[1] << 8 | sei.payload[2]) !== 49) {\n return null;\n } // the user_identifier should be \"GA94\" to indicate ATSC1 data\n\n\n if (String.fromCharCode(sei.payload[3], sei.payload[4], sei.payload[5], sei.payload[6]) !== 'GA94') {\n return null;\n } // finally, user_data_type_code should be 0x03 for caption data\n\n\n if (sei.payload[7] !== 0x03) {\n return null;\n } // return the user_data_type_structure and strip the trailing\n // marker bits\n\n\n return sei.payload.subarray(8, sei.payload.length - 1);\n }; // see CEA-708-D, section 4.4\n\n\n var parseCaptionPackets = function (pts, userData) {\n var results = [],\n i,\n count,\n offset,\n data; // if this is just filler, return immediately\n\n if (!(userData[0] & 0x40)) {\n return results;\n } // parse out the cc_data_1 and cc_data_2 fields\n\n\n count = userData[0] & 0x1f;\n\n for (i = 0; i < count; i++) {\n offset = i * 3;\n data = {\n type: userData[offset + 2] & 0x03,\n pts: pts\n }; // capture cc data when cc_valid is 1\n\n if (userData[offset + 2] & 0x04) {\n data.ccData = userData[offset + 3] << 8 | userData[offset + 4];\n results.push(data);\n }\n }\n\n return results;\n };\n\n var discardEmulationPreventionBytes$1 = function (data) {\n var length = data.byteLength,\n emulationPreventionBytesPositions = [],\n i = 1,\n newLength,\n newData; // Find all `Emulation Prevention Bytes`\n\n while (i < length - 2) {\n if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {\n emulationPreventionBytesPositions.push(i + 2);\n i += 2;\n } else {\n i++;\n }\n } // If no Emulation Prevention Bytes were found just return the original\n // array\n\n\n if (emulationPreventionBytesPositions.length === 0) {\n return data;\n } // Create a new array to hold the NAL unit data\n\n\n newLength = length - emulationPreventionBytesPositions.length;\n newData = new Uint8Array(newLength);\n var sourceIndex = 0;\n\n for (i = 0; i < newLength; sourceIndex++, i++) {\n if (sourceIndex === emulationPreventionBytesPositions[0]) {\n // Skip this byte\n sourceIndex++; // Remove this position index\n\n emulationPreventionBytesPositions.shift();\n }\n\n newData[i] = data[sourceIndex];\n }\n\n return newData;\n }; // exports\n\n\n var captionPacketParser = {\n parseSei: parseSei,\n parseUserData: parseUserData,\n parseCaptionPackets: parseCaptionPackets,\n discardEmulationPreventionBytes: discardEmulationPreventionBytes$1,\n USER_DATA_REGISTERED_ITU_T_T35: USER_DATA_REGISTERED_ITU_T_T35\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Reads in-band caption information from a video elementary\n * stream. Captions must follow the CEA-708 standard for injection\n * into an MPEG-2 transport streams.\n * @see https://en.wikipedia.org/wiki/CEA-708\n * @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf\n */\n // Link To Transport\n // -----------------\n\n var Stream$7 = stream;\n var cea708Parser = captionPacketParser;\n\n var CaptionStream$2 = function (options) {\n options = options || {};\n CaptionStream$2.prototype.init.call(this); // parse708captions flag, default to true\n\n this.parse708captions_ = typeof options.parse708captions === 'boolean' ? options.parse708captions : true;\n this.captionPackets_ = [];\n this.ccStreams_ = [new Cea608Stream(0, 0), // eslint-disable-line no-use-before-define\n new Cea608Stream(0, 1), // eslint-disable-line no-use-before-define\n new Cea608Stream(1, 0), // eslint-disable-line no-use-before-define\n new Cea608Stream(1, 1) // eslint-disable-line no-use-before-define\n ];\n\n if (this.parse708captions_) {\n this.cc708Stream_ = new Cea708Stream({\n captionServices: options.captionServices\n }); // eslint-disable-line no-use-before-define\n }\n\n this.reset(); // forward data and done events from CCs to this CaptionStream\n\n this.ccStreams_.forEach(function (cc) {\n cc.on('data', this.trigger.bind(this, 'data'));\n cc.on('partialdone', this.trigger.bind(this, 'partialdone'));\n cc.on('done', this.trigger.bind(this, 'done'));\n }, this);\n\n if (this.parse708captions_) {\n this.cc708Stream_.on('data', this.trigger.bind(this, 'data'));\n this.cc708Stream_.on('partialdone', this.trigger.bind(this, 'partialdone'));\n this.cc708Stream_.on('done', this.trigger.bind(this, 'done'));\n }\n };\n\n CaptionStream$2.prototype = new Stream$7();\n\n CaptionStream$2.prototype.push = function (event) {\n var sei, userData, newCaptionPackets; // only examine SEI NALs\n\n if (event.nalUnitType !== 'sei_rbsp') {\n return;\n } // parse the sei\n\n\n sei = cea708Parser.parseSei(event.escapedRBSP); // no payload data, skip\n\n if (!sei.payload) {\n return;\n } // ignore everything but user_data_registered_itu_t_t35\n\n\n if (sei.payloadType !== cea708Parser.USER_DATA_REGISTERED_ITU_T_T35) {\n return;\n } // parse out the user data payload\n\n\n userData = cea708Parser.parseUserData(sei); // ignore unrecognized userData\n\n if (!userData) {\n return;\n } // Sometimes, the same segment # will be downloaded twice. To stop the\n // caption data from being processed twice, we track the latest dts we've\n // received and ignore everything with a dts before that. However, since\n // data for a specific dts can be split across packets on either side of\n // a segment boundary, we need to make sure we *don't* ignore the packets\n // from the *next* segment that have dts === this.latestDts_. By constantly\n // tracking the number of packets received with dts === this.latestDts_, we\n // know how many should be ignored once we start receiving duplicates.\n\n\n if (event.dts < this.latestDts_) {\n // We've started getting older data, so set the flag.\n this.ignoreNextEqualDts_ = true;\n return;\n } else if (event.dts === this.latestDts_ && this.ignoreNextEqualDts_) {\n this.numSameDts_--;\n\n if (!this.numSameDts_) {\n // We've received the last duplicate packet, time to start processing again\n this.ignoreNextEqualDts_ = false;\n }\n\n return;\n } // parse out CC data packets and save them for later\n\n\n newCaptionPackets = cea708Parser.parseCaptionPackets(event.pts, userData);\n this.captionPackets_ = this.captionPackets_.concat(newCaptionPackets);\n\n if (this.latestDts_ !== event.dts) {\n this.numSameDts_ = 0;\n }\n\n this.numSameDts_++;\n this.latestDts_ = event.dts;\n };\n\n CaptionStream$2.prototype.flushCCStreams = function (flushType) {\n this.ccStreams_.forEach(function (cc) {\n return flushType === 'flush' ? cc.flush() : cc.partialFlush();\n }, this);\n };\n\n CaptionStream$2.prototype.flushStream = function (flushType) {\n // make sure we actually parsed captions before proceeding\n if (!this.captionPackets_.length) {\n this.flushCCStreams(flushType);\n return;\n } // In Chrome, the Array#sort function is not stable so add a\n // presortIndex that we can use to ensure we get a stable-sort\n\n\n this.captionPackets_.forEach(function (elem, idx) {\n elem.presortIndex = idx;\n }); // sort caption byte-pairs based on their PTS values\n\n this.captionPackets_.sort(function (a, b) {\n if (a.pts === b.pts) {\n return a.presortIndex - b.presortIndex;\n }\n\n return a.pts - b.pts;\n });\n this.captionPackets_.forEach(function (packet) {\n if (packet.type < 2) {\n // Dispatch packet to the right Cea608Stream\n this.dispatchCea608Packet(packet);\n } else {\n // Dispatch packet to the Cea708Stream\n this.dispatchCea708Packet(packet);\n }\n }, this);\n this.captionPackets_.length = 0;\n this.flushCCStreams(flushType);\n };\n\n CaptionStream$2.prototype.flush = function () {\n return this.flushStream('flush');\n }; // Only called if handling partial data\n\n\n CaptionStream$2.prototype.partialFlush = function () {\n return this.flushStream('partialFlush');\n };\n\n CaptionStream$2.prototype.reset = function () {\n this.latestDts_ = null;\n this.ignoreNextEqualDts_ = false;\n this.numSameDts_ = 0;\n this.activeCea608Channel_ = [null, null];\n this.ccStreams_.forEach(function (ccStream) {\n ccStream.reset();\n });\n }; // From the CEA-608 spec:\n\n /*\n * When XDS sub-packets are interleaved with other services, the end of each sub-packet shall be followed\n * by a control pair to change to a different service. When any of the control codes from 0x10 to 0x1F is\n * used to begin a control code pair, it indicates the return to captioning or Text data. The control code pair\n * and subsequent data should then be processed according to the FCC rules. It may be necessary for the\n * line 21 data encoder to automatically insert a control code pair (i.e. RCL, RU2, RU3, RU4, RDC, or RTD)\n * to switch to captioning or Text.\n */\n // With that in mind, we ignore any data between an XDS control code and a\n // subsequent closed-captioning control code.\n\n\n CaptionStream$2.prototype.dispatchCea608Packet = function (packet) {\n // NOTE: packet.type is the CEA608 field\n if (this.setsTextOrXDSActive(packet)) {\n this.activeCea608Channel_[packet.type] = null;\n } else if (this.setsChannel1Active(packet)) {\n this.activeCea608Channel_[packet.type] = 0;\n } else if (this.setsChannel2Active(packet)) {\n this.activeCea608Channel_[packet.type] = 1;\n }\n\n if (this.activeCea608Channel_[packet.type] === null) {\n // If we haven't received anything to set the active channel, or the\n // packets are Text/XDS data, discard the data; we don't want jumbled\n // captions\n return;\n }\n\n this.ccStreams_[(packet.type << 1) + this.activeCea608Channel_[packet.type]].push(packet);\n };\n\n CaptionStream$2.prototype.setsChannel1Active = function (packet) {\n return (packet.ccData & 0x7800) === 0x1000;\n };\n\n CaptionStream$2.prototype.setsChannel2Active = function (packet) {\n return (packet.ccData & 0x7800) === 0x1800;\n };\n\n CaptionStream$2.prototype.setsTextOrXDSActive = function (packet) {\n return (packet.ccData & 0x7100) === 0x0100 || (packet.ccData & 0x78fe) === 0x102a || (packet.ccData & 0x78fe) === 0x182a;\n };\n\n CaptionStream$2.prototype.dispatchCea708Packet = function (packet) {\n if (this.parse708captions_) {\n this.cc708Stream_.push(packet);\n }\n }; // ----------------------\n // Session to Application\n // ----------------------\n // This hash maps special and extended character codes to their\n // proper Unicode equivalent. The first one-byte key is just a\n // non-standard character code. The two-byte keys that follow are\n // the extended CEA708 character codes, along with the preceding\n // 0x10 extended character byte to distinguish these codes from\n // non-extended character codes. Every CEA708 character code that\n // is not in this object maps directly to a standard unicode\n // character code.\n // The transparent space and non-breaking transparent space are\n // technically not fully supported since there is no code to\n // make them transparent, so they have normal non-transparent\n // stand-ins.\n // The special closed caption (CC) character isn't a standard\n // unicode character, so a fairly similar unicode character was\n // chosen in it's place.\n\n\n var CHARACTER_TRANSLATION_708 = {\n 0x7f: 0x266a,\n // ♪\n 0x1020: 0x20,\n // Transparent Space\n 0x1021: 0xa0,\n // Nob-breaking Transparent Space\n 0x1025: 0x2026,\n // …\n 0x102a: 0x0160,\n // Š\n 0x102c: 0x0152,\n // Œ\n 0x1030: 0x2588,\n // █\n 0x1031: 0x2018,\n // ‘\n 0x1032: 0x2019,\n // ’\n 0x1033: 0x201c,\n // “\n 0x1034: 0x201d,\n // ”\n 0x1035: 0x2022,\n // •\n 0x1039: 0x2122,\n // ™\n 0x103a: 0x0161,\n // š\n 0x103c: 0x0153,\n // œ\n 0x103d: 0x2120,\n // ℠\n 0x103f: 0x0178,\n // Ÿ\n 0x1076: 0x215b,\n // ⅛\n 0x1077: 0x215c,\n // ⅜\n 0x1078: 0x215d,\n // ⅝\n 0x1079: 0x215e,\n // ⅞\n 0x107a: 0x23d0,\n // ⏐\n 0x107b: 0x23a4,\n // ⎤\n 0x107c: 0x23a3,\n // ⎣\n 0x107d: 0x23af,\n // ⎯\n 0x107e: 0x23a6,\n // ⎦\n 0x107f: 0x23a1,\n // ⎡\n 0x10a0: 0x3138 // ㄸ (CC char)\n\n };\n\n var get708CharFromCode = function (code) {\n var newCode = CHARACTER_TRANSLATION_708[code] || code;\n\n if (code & 0x1000 && code === newCode) {\n // Invalid extended code\n return '';\n }\n\n return String.fromCharCode(newCode);\n };\n\n var within708TextBlock = function (b) {\n return 0x20 <= b && b <= 0x7f || 0xa0 <= b && b <= 0xff;\n };\n\n var Cea708Window = function (windowNum) {\n this.windowNum = windowNum;\n this.reset();\n };\n\n Cea708Window.prototype.reset = function () {\n this.clearText();\n this.pendingNewLine = false;\n this.winAttr = {};\n this.penAttr = {};\n this.penLoc = {};\n this.penColor = {}; // These default values are arbitrary,\n // defineWindow will usually override them\n\n this.visible = 0;\n this.rowLock = 0;\n this.columnLock = 0;\n this.priority = 0;\n this.relativePositioning = 0;\n this.anchorVertical = 0;\n this.anchorHorizontal = 0;\n this.anchorPoint = 0;\n this.rowCount = 1;\n this.virtualRowCount = this.rowCount + 1;\n this.columnCount = 41;\n this.windowStyle = 0;\n this.penStyle = 0;\n };\n\n Cea708Window.prototype.getText = function () {\n return this.rows.join('\\n');\n };\n\n Cea708Window.prototype.clearText = function () {\n this.rows = [''];\n this.rowIdx = 0;\n };\n\n Cea708Window.prototype.newLine = function (pts) {\n if (this.rows.length >= this.virtualRowCount && typeof this.beforeRowOverflow === 'function') {\n this.beforeRowOverflow(pts);\n }\n\n if (this.rows.length > 0) {\n this.rows.push('');\n this.rowIdx++;\n } // Show all virtual rows since there's no visible scrolling\n\n\n while (this.rows.length > this.virtualRowCount) {\n this.rows.shift();\n this.rowIdx--;\n }\n };\n\n Cea708Window.prototype.isEmpty = function () {\n if (this.rows.length === 0) {\n return true;\n } else if (this.rows.length === 1) {\n return this.rows[0] === '';\n }\n\n return false;\n };\n\n Cea708Window.prototype.addText = function (text) {\n this.rows[this.rowIdx] += text;\n };\n\n Cea708Window.prototype.backspace = function () {\n if (!this.isEmpty()) {\n var row = this.rows[this.rowIdx];\n this.rows[this.rowIdx] = row.substr(0, row.length - 1);\n }\n };\n\n var Cea708Service = function (serviceNum, encoding, stream) {\n this.serviceNum = serviceNum;\n this.text = '';\n this.currentWindow = new Cea708Window(-1);\n this.windows = [];\n this.stream = stream; // Try to setup a TextDecoder if an `encoding` value was provided\n\n if (typeof encoding === 'string') {\n this.createTextDecoder(encoding);\n }\n };\n /**\n * Initialize service windows\n * Must be run before service use\n *\n * @param {Integer} pts PTS value\n * @param {Function} beforeRowOverflow Function to execute before row overflow of a window\n */\n\n\n Cea708Service.prototype.init = function (pts, beforeRowOverflow) {\n this.startPts = pts;\n\n for (var win = 0; win < 8; win++) {\n this.windows[win] = new Cea708Window(win);\n\n if (typeof beforeRowOverflow === 'function') {\n this.windows[win].beforeRowOverflow = beforeRowOverflow;\n }\n }\n };\n /**\n * Set current window of service to be affected by commands\n *\n * @param {Integer} windowNum Window number\n */\n\n\n Cea708Service.prototype.setCurrentWindow = function (windowNum) {\n this.currentWindow = this.windows[windowNum];\n };\n /**\n * Try to create a TextDecoder if it is natively supported\n */\n\n\n Cea708Service.prototype.createTextDecoder = function (encoding) {\n if (typeof TextDecoder === 'undefined') {\n this.stream.trigger('log', {\n level: 'warn',\n message: 'The `encoding` option is unsupported without TextDecoder support'\n });\n } else {\n try {\n this.textDecoder_ = new TextDecoder(encoding);\n } catch (error) {\n this.stream.trigger('log', {\n level: 'warn',\n message: 'TextDecoder could not be created with ' + encoding + ' encoding. ' + error\n });\n }\n }\n };\n\n var Cea708Stream = function (options) {\n options = options || {};\n Cea708Stream.prototype.init.call(this);\n var self = this;\n var captionServices = options.captionServices || {};\n var captionServiceEncodings = {};\n var serviceProps; // Get service encodings from captionServices option block\n\n Object.keys(captionServices).forEach(serviceName => {\n serviceProps = captionServices[serviceName];\n\n if (/^SERVICE/.test(serviceName)) {\n captionServiceEncodings[serviceName] = serviceProps.encoding;\n }\n });\n this.serviceEncodings = captionServiceEncodings;\n this.current708Packet = null;\n this.services = {};\n\n this.push = function (packet) {\n if (packet.type === 3) {\n // 708 packet start\n self.new708Packet();\n self.add708Bytes(packet);\n } else {\n if (self.current708Packet === null) {\n // This should only happen at the start of a file if there's no packet start.\n self.new708Packet();\n }\n\n self.add708Bytes(packet);\n }\n };\n };\n\n Cea708Stream.prototype = new Stream$7();\n /**\n * Push current 708 packet, create new 708 packet.\n */\n\n Cea708Stream.prototype.new708Packet = function () {\n if (this.current708Packet !== null) {\n this.push708Packet();\n }\n\n this.current708Packet = {\n data: [],\n ptsVals: []\n };\n };\n /**\n * Add pts and both bytes from packet into current 708 packet.\n */\n\n\n Cea708Stream.prototype.add708Bytes = function (packet) {\n var data = packet.ccData;\n var byte0 = data >>> 8;\n var byte1 = data & 0xff; // I would just keep a list of packets instead of bytes, but it isn't clear in the spec\n // that service blocks will always line up with byte pairs.\n\n this.current708Packet.ptsVals.push(packet.pts);\n this.current708Packet.data.push(byte0);\n this.current708Packet.data.push(byte1);\n };\n /**\n * Parse completed 708 packet into service blocks and push each service block.\n */\n\n\n Cea708Stream.prototype.push708Packet = function () {\n var packet708 = this.current708Packet;\n var packetData = packet708.data;\n var serviceNum = null;\n var blockSize = null;\n var i = 0;\n var b = packetData[i++];\n packet708.seq = b >> 6;\n packet708.sizeCode = b & 0x3f; // 0b00111111;\n\n for (; i < packetData.length; i++) {\n b = packetData[i++];\n serviceNum = b >> 5;\n blockSize = b & 0x1f; // 0b00011111\n\n if (serviceNum === 7 && blockSize > 0) {\n // Extended service num\n b = packetData[i++];\n serviceNum = b;\n }\n\n this.pushServiceBlock(serviceNum, i, blockSize);\n\n if (blockSize > 0) {\n i += blockSize - 1;\n }\n }\n };\n /**\n * Parse service block, execute commands, read text.\n *\n * Note: While many of these commands serve important purposes,\n * many others just parse out the parameters or attributes, but\n * nothing is done with them because this is not a full and complete\n * implementation of the entire 708 spec.\n *\n * @param {Integer} serviceNum Service number\n * @param {Integer} start Start index of the 708 packet data\n * @param {Integer} size Block size\n */\n\n\n Cea708Stream.prototype.pushServiceBlock = function (serviceNum, start, size) {\n var b;\n var i = start;\n var packetData = this.current708Packet.data;\n var service = this.services[serviceNum];\n\n if (!service) {\n service = this.initService(serviceNum, i);\n }\n\n for (; i < start + size && i < packetData.length; i++) {\n b = packetData[i];\n\n if (within708TextBlock(b)) {\n i = this.handleText(i, service);\n } else if (b === 0x18) {\n i = this.multiByteCharacter(i, service);\n } else if (b === 0x10) {\n i = this.extendedCommands(i, service);\n } else if (0x80 <= b && b <= 0x87) {\n i = this.setCurrentWindow(i, service);\n } else if (0x98 <= b && b <= 0x9f) {\n i = this.defineWindow(i, service);\n } else if (b === 0x88) {\n i = this.clearWindows(i, service);\n } else if (b === 0x8c) {\n i = this.deleteWindows(i, service);\n } else if (b === 0x89) {\n i = this.displayWindows(i, service);\n } else if (b === 0x8a) {\n i = this.hideWindows(i, service);\n } else if (b === 0x8b) {\n i = this.toggleWindows(i, service);\n } else if (b === 0x97) {\n i = this.setWindowAttributes(i, service);\n } else if (b === 0x90) {\n i = this.setPenAttributes(i, service);\n } else if (b === 0x91) {\n i = this.setPenColor(i, service);\n } else if (b === 0x92) {\n i = this.setPenLocation(i, service);\n } else if (b === 0x8f) {\n service = this.reset(i, service);\n } else if (b === 0x08) {\n // BS: Backspace\n service.currentWindow.backspace();\n } else if (b === 0x0c) {\n // FF: Form feed\n service.currentWindow.clearText();\n } else if (b === 0x0d) {\n // CR: Carriage return\n service.currentWindow.pendingNewLine = true;\n } else if (b === 0x0e) {\n // HCR: Horizontal carriage return\n service.currentWindow.clearText();\n } else if (b === 0x8d) {\n // DLY: Delay, nothing to do\n i++;\n } else ;\n }\n };\n /**\n * Execute an extended command\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.extendedCommands = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n\n if (within708TextBlock(b)) {\n i = this.handleText(i, service, {\n isExtended: true\n });\n }\n\n return i;\n };\n /**\n * Get PTS value of a given byte index\n *\n * @param {Integer} byteIndex Index of the byte\n * @return {Integer} PTS\n */\n\n\n Cea708Stream.prototype.getPts = function (byteIndex) {\n // There's 1 pts value per 2 bytes\n return this.current708Packet.ptsVals[Math.floor(byteIndex / 2)];\n };\n /**\n * Initializes a service\n *\n * @param {Integer} serviceNum Service number\n * @return {Service} Initialized service object\n */\n\n\n Cea708Stream.prototype.initService = function (serviceNum, i) {\n var serviceName = 'SERVICE' + serviceNum;\n var self = this;\n var serviceName;\n var encoding;\n\n if (serviceName in this.serviceEncodings) {\n encoding = this.serviceEncodings[serviceName];\n }\n\n this.services[serviceNum] = new Cea708Service(serviceNum, encoding, self);\n this.services[serviceNum].init(this.getPts(i), function (pts) {\n self.flushDisplayed(pts, self.services[serviceNum]);\n });\n return this.services[serviceNum];\n };\n /**\n * Execute text writing to current window\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.handleText = function (i, service, options) {\n var isExtended = options && options.isExtended;\n var isMultiByte = options && options.isMultiByte;\n var packetData = this.current708Packet.data;\n var extended = isExtended ? 0x1000 : 0x0000;\n var currentByte = packetData[i];\n var nextByte = packetData[i + 1];\n var win = service.currentWindow;\n var char;\n var charCodeArray; // Converts an array of bytes to a unicode hex string.\n\n function toHexString(byteArray) {\n return byteArray.map(byte => {\n return ('0' + (byte & 0xFF).toString(16)).slice(-2);\n }).join('');\n }\n\n if (isMultiByte) {\n charCodeArray = [currentByte, nextByte];\n i++;\n } else {\n charCodeArray = [currentByte];\n } // Use the TextDecoder if one was created for this service\n\n\n if (service.textDecoder_ && !isExtended) {\n char = service.textDecoder_.decode(new Uint8Array(charCodeArray));\n } else {\n // We assume any multi-byte char without a decoder is unicode.\n if (isMultiByte) {\n const unicode = toHexString(charCodeArray); // Takes a unicode hex string and creates a single character.\n\n char = String.fromCharCode(parseInt(unicode, 16));\n } else {\n char = get708CharFromCode(extended | currentByte);\n }\n }\n\n if (win.pendingNewLine && !win.isEmpty()) {\n win.newLine(this.getPts(i));\n }\n\n win.pendingNewLine = false;\n win.addText(char);\n return i;\n };\n /**\n * Handle decoding of multibyte character\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.multiByteCharacter = function (i, service) {\n var packetData = this.current708Packet.data;\n var firstByte = packetData[i + 1];\n var secondByte = packetData[i + 2];\n\n if (within708TextBlock(firstByte) && within708TextBlock(secondByte)) {\n i = this.handleText(++i, service, {\n isMultiByte: true\n });\n }\n\n return i;\n };\n /**\n * Parse and execute the CW# command.\n *\n * Set the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.setCurrentWindow = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var windowNum = b & 0x07;\n service.setCurrentWindow(windowNum);\n return i;\n };\n /**\n * Parse and execute the DF# command.\n *\n * Define a window and set it as the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.defineWindow = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var windowNum = b & 0x07;\n service.setCurrentWindow(windowNum);\n var win = service.currentWindow;\n b = packetData[++i];\n win.visible = (b & 0x20) >> 5; // v\n\n win.rowLock = (b & 0x10) >> 4; // rl\n\n win.columnLock = (b & 0x08) >> 3; // cl\n\n win.priority = b & 0x07; // p\n\n b = packetData[++i];\n win.relativePositioning = (b & 0x80) >> 7; // rp\n\n win.anchorVertical = b & 0x7f; // av\n\n b = packetData[++i];\n win.anchorHorizontal = b; // ah\n\n b = packetData[++i];\n win.anchorPoint = (b & 0xf0) >> 4; // ap\n\n win.rowCount = b & 0x0f; // rc\n\n b = packetData[++i];\n win.columnCount = b & 0x3f; // cc\n\n b = packetData[++i];\n win.windowStyle = (b & 0x38) >> 3; // ws\n\n win.penStyle = b & 0x07; // ps\n // The spec says there are (rowCount+1) \"virtual rows\"\n\n win.virtualRowCount = win.rowCount + 1;\n return i;\n };\n /**\n * Parse and execute the SWA command.\n *\n * Set attributes of the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.setWindowAttributes = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var winAttr = service.currentWindow.winAttr;\n b = packetData[++i];\n winAttr.fillOpacity = (b & 0xc0) >> 6; // fo\n\n winAttr.fillRed = (b & 0x30) >> 4; // fr\n\n winAttr.fillGreen = (b & 0x0c) >> 2; // fg\n\n winAttr.fillBlue = b & 0x03; // fb\n\n b = packetData[++i];\n winAttr.borderType = (b & 0xc0) >> 6; // bt\n\n winAttr.borderRed = (b & 0x30) >> 4; // br\n\n winAttr.borderGreen = (b & 0x0c) >> 2; // bg\n\n winAttr.borderBlue = b & 0x03; // bb\n\n b = packetData[++i];\n winAttr.borderType += (b & 0x80) >> 5; // bt\n\n winAttr.wordWrap = (b & 0x40) >> 6; // ww\n\n winAttr.printDirection = (b & 0x30) >> 4; // pd\n\n winAttr.scrollDirection = (b & 0x0c) >> 2; // sd\n\n winAttr.justify = b & 0x03; // j\n\n b = packetData[++i];\n winAttr.effectSpeed = (b & 0xf0) >> 4; // es\n\n winAttr.effectDirection = (b & 0x0c) >> 2; // ed\n\n winAttr.displayEffect = b & 0x03; // de\n\n return i;\n };\n /**\n * Gather text from all displayed windows and push a caption to output.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n */\n\n\n Cea708Stream.prototype.flushDisplayed = function (pts, service) {\n var displayedText = []; // TODO: Positioning not supported, displaying multiple windows will not necessarily\n // display text in the correct order, but sample files so far have not shown any issue.\n\n for (var winId = 0; winId < 8; winId++) {\n if (service.windows[winId].visible && !service.windows[winId].isEmpty()) {\n displayedText.push(service.windows[winId].getText());\n }\n }\n\n service.endPts = pts;\n service.text = displayedText.join('\\n\\n');\n this.pushCaption(service);\n service.startPts = pts;\n };\n /**\n * Push a caption to output if the caption contains text.\n *\n * @param {Service} service The service object to be affected\n */\n\n\n Cea708Stream.prototype.pushCaption = function (service) {\n if (service.text !== '') {\n this.trigger('data', {\n startPts: service.startPts,\n endPts: service.endPts,\n text: service.text,\n stream: 'cc708_' + service.serviceNum\n });\n service.text = '';\n service.startPts = service.endPts;\n }\n };\n /**\n * Parse and execute the DSW command.\n *\n * Set visible property of windows based on the parsed bitmask.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.displayWindows = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n\n for (var winId = 0; winId < 8; winId++) {\n if (b & 0x01 << winId) {\n service.windows[winId].visible = 1;\n }\n }\n\n return i;\n };\n /**\n * Parse and execute the HDW command.\n *\n * Set visible property of windows based on the parsed bitmask.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.hideWindows = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n\n for (var winId = 0; winId < 8; winId++) {\n if (b & 0x01 << winId) {\n service.windows[winId].visible = 0;\n }\n }\n\n return i;\n };\n /**\n * Parse and execute the TGW command.\n *\n * Set visible property of windows based on the parsed bitmask.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.toggleWindows = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n\n for (var winId = 0; winId < 8; winId++) {\n if (b & 0x01 << winId) {\n service.windows[winId].visible ^= 1;\n }\n }\n\n return i;\n };\n /**\n * Parse and execute the CLW command.\n *\n * Clear text of windows based on the parsed bitmask.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.clearWindows = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n\n for (var winId = 0; winId < 8; winId++) {\n if (b & 0x01 << winId) {\n service.windows[winId].clearText();\n }\n }\n\n return i;\n };\n /**\n * Parse and execute the DLW command.\n *\n * Re-initialize windows based on the parsed bitmask.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.deleteWindows = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[++i];\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n\n for (var winId = 0; winId < 8; winId++) {\n if (b & 0x01 << winId) {\n service.windows[winId].reset();\n }\n }\n\n return i;\n };\n /**\n * Parse and execute the SPA command.\n *\n * Set pen attributes of the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.setPenAttributes = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var penAttr = service.currentWindow.penAttr;\n b = packetData[++i];\n penAttr.textTag = (b & 0xf0) >> 4; // tt\n\n penAttr.offset = (b & 0x0c) >> 2; // o\n\n penAttr.penSize = b & 0x03; // s\n\n b = packetData[++i];\n penAttr.italics = (b & 0x80) >> 7; // i\n\n penAttr.underline = (b & 0x40) >> 6; // u\n\n penAttr.edgeType = (b & 0x38) >> 3; // et\n\n penAttr.fontStyle = b & 0x07; // fs\n\n return i;\n };\n /**\n * Parse and execute the SPC command.\n *\n * Set pen color of the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.setPenColor = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var penColor = service.currentWindow.penColor;\n b = packetData[++i];\n penColor.fgOpacity = (b & 0xc0) >> 6; // fo\n\n penColor.fgRed = (b & 0x30) >> 4; // fr\n\n penColor.fgGreen = (b & 0x0c) >> 2; // fg\n\n penColor.fgBlue = b & 0x03; // fb\n\n b = packetData[++i];\n penColor.bgOpacity = (b & 0xc0) >> 6; // bo\n\n penColor.bgRed = (b & 0x30) >> 4; // br\n\n penColor.bgGreen = (b & 0x0c) >> 2; // bg\n\n penColor.bgBlue = b & 0x03; // bb\n\n b = packetData[++i];\n penColor.edgeRed = (b & 0x30) >> 4; // er\n\n penColor.edgeGreen = (b & 0x0c) >> 2; // eg\n\n penColor.edgeBlue = b & 0x03; // eb\n\n return i;\n };\n /**\n * Parse and execute the SPL command.\n *\n * Set pen location of the current window.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Integer} New index after parsing\n */\n\n\n Cea708Stream.prototype.setPenLocation = function (i, service) {\n var packetData = this.current708Packet.data;\n var b = packetData[i];\n var penLoc = service.currentWindow.penLoc; // Positioning isn't really supported at the moment, so this essentially just inserts a linebreak\n\n service.currentWindow.pendingNewLine = true;\n b = packetData[++i];\n penLoc.row = b & 0x0f; // r\n\n b = packetData[++i];\n penLoc.column = b & 0x3f; // c\n\n return i;\n };\n /**\n * Execute the RST command.\n *\n * Reset service to a clean slate. Re-initialize.\n *\n * @param {Integer} i Current index in the 708 packet\n * @param {Service} service The service object to be affected\n * @return {Service} Re-initialized service\n */\n\n\n Cea708Stream.prototype.reset = function (i, service) {\n var pts = this.getPts(i);\n this.flushDisplayed(pts, service);\n return this.initService(service.serviceNum, i);\n }; // This hash maps non-ASCII, special, and extended character codes to their\n // proper Unicode equivalent. The first keys that are only a single byte\n // are the non-standard ASCII characters, which simply map the CEA608 byte\n // to the standard ASCII/Unicode. The two-byte keys that follow are the CEA608\n // character codes, but have their MSB bitmasked with 0x03 so that a lookup\n // can be performed regardless of the field and data channel on which the\n // character code was received.\n\n\n var CHARACTER_TRANSLATION = {\n 0x2a: 0xe1,\n // á\n 0x5c: 0xe9,\n // é\n 0x5e: 0xed,\n // í\n 0x5f: 0xf3,\n // ó\n 0x60: 0xfa,\n // ú\n 0x7b: 0xe7,\n // ç\n 0x7c: 0xf7,\n // ÷\n 0x7d: 0xd1,\n // Ñ\n 0x7e: 0xf1,\n // ñ\n 0x7f: 0x2588,\n // █\n 0x0130: 0xae,\n // ®\n 0x0131: 0xb0,\n // °\n 0x0132: 0xbd,\n // ½\n 0x0133: 0xbf,\n // ¿\n 0x0134: 0x2122,\n // ™\n 0x0135: 0xa2,\n // ¢\n 0x0136: 0xa3,\n // £\n 0x0137: 0x266a,\n // ♪\n 0x0138: 0xe0,\n // à\n 0x0139: 0xa0,\n //\n 0x013a: 0xe8,\n // è\n 0x013b: 0xe2,\n // â\n 0x013c: 0xea,\n // ê\n 0x013d: 0xee,\n // î\n 0x013e: 0xf4,\n // ô\n 0x013f: 0xfb,\n // û\n 0x0220: 0xc1,\n // Á\n 0x0221: 0xc9,\n // É\n 0x0222: 0xd3,\n // Ó\n 0x0223: 0xda,\n // Ú\n 0x0224: 0xdc,\n // Ü\n 0x0225: 0xfc,\n // ü\n 0x0226: 0x2018,\n // ‘\n 0x0227: 0xa1,\n // ¡\n 0x0228: 0x2a,\n // *\n 0x0229: 0x27,\n // '\n 0x022a: 0x2014,\n // —\n 0x022b: 0xa9,\n // ©\n 0x022c: 0x2120,\n // ℠\n 0x022d: 0x2022,\n // •\n 0x022e: 0x201c,\n // “\n 0x022f: 0x201d,\n // ”\n 0x0230: 0xc0,\n // À\n 0x0231: 0xc2,\n // Â\n 0x0232: 0xc7,\n // Ç\n 0x0233: 0xc8,\n // È\n 0x0234: 0xca,\n // Ê\n 0x0235: 0xcb,\n // Ë\n 0x0236: 0xeb,\n // ë\n 0x0237: 0xce,\n // Î\n 0x0238: 0xcf,\n // Ï\n 0x0239: 0xef,\n // ï\n 0x023a: 0xd4,\n // Ô\n 0x023b: 0xd9,\n // Ù\n 0x023c: 0xf9,\n // ù\n 0x023d: 0xdb,\n // Û\n 0x023e: 0xab,\n // «\n 0x023f: 0xbb,\n // »\n 0x0320: 0xc3,\n // Ã\n 0x0321: 0xe3,\n // ã\n 0x0322: 0xcd,\n // Í\n 0x0323: 0xcc,\n // Ì\n 0x0324: 0xec,\n // ì\n 0x0325: 0xd2,\n // Ò\n 0x0326: 0xf2,\n // ò\n 0x0327: 0xd5,\n // Õ\n 0x0328: 0xf5,\n // õ\n 0x0329: 0x7b,\n // {\n 0x032a: 0x7d,\n // }\n 0x032b: 0x5c,\n // \\\n 0x032c: 0x5e,\n // ^\n 0x032d: 0x5f,\n // _\n 0x032e: 0x7c,\n // |\n 0x032f: 0x7e,\n // ~\n 0x0330: 0xc4,\n // Ä\n 0x0331: 0xe4,\n // ä\n 0x0332: 0xd6,\n // Ö\n 0x0333: 0xf6,\n // ö\n 0x0334: 0xdf,\n // ß\n 0x0335: 0xa5,\n // ¥\n 0x0336: 0xa4,\n // ¤\n 0x0337: 0x2502,\n // │\n 0x0338: 0xc5,\n // Å\n 0x0339: 0xe5,\n // å\n 0x033a: 0xd8,\n // Ø\n 0x033b: 0xf8,\n // ø\n 0x033c: 0x250c,\n // ┌\n 0x033d: 0x2510,\n // ┐\n 0x033e: 0x2514,\n // └\n 0x033f: 0x2518 // ┘\n\n };\n\n var getCharFromCode = function (code) {\n if (code === null) {\n return '';\n }\n\n code = CHARACTER_TRANSLATION[code] || code;\n return String.fromCharCode(code);\n }; // the index of the last row in a CEA-608 display buffer\n\n\n var BOTTOM_ROW = 14; // This array is used for mapping PACs -> row #, since there's no way of\n // getting it through bit logic.\n\n var ROWS = [0x1100, 0x1120, 0x1200, 0x1220, 0x1500, 0x1520, 0x1600, 0x1620, 0x1700, 0x1720, 0x1000, 0x1300, 0x1320, 0x1400, 0x1420]; // CEA-608 captions are rendered onto a 34x15 matrix of character\n // cells. The \"bottom\" row is the last element in the outer array.\n // We keep track of positioning information as we go by storing the\n // number of indentations and the tab offset in this buffer.\n\n var createDisplayBuffer = function () {\n var result = [],\n i = BOTTOM_ROW + 1;\n\n while (i--) {\n result.push({\n text: '',\n indent: 0,\n offset: 0\n });\n }\n\n return result;\n };\n\n var Cea608Stream = function (field, dataChannel) {\n Cea608Stream.prototype.init.call(this);\n this.field_ = field || 0;\n this.dataChannel_ = dataChannel || 0;\n this.name_ = 'CC' + ((this.field_ << 1 | this.dataChannel_) + 1);\n this.setConstants();\n this.reset();\n\n this.push = function (packet) {\n var data, swap, char0, char1, text; // remove the parity bits\n\n data = packet.ccData & 0x7f7f; // ignore duplicate control codes; the spec demands they're sent twice\n\n if (data === this.lastControlCode_) {\n this.lastControlCode_ = null;\n return;\n } // Store control codes\n\n\n if ((data & 0xf000) === 0x1000) {\n this.lastControlCode_ = data;\n } else if (data !== this.PADDING_) {\n this.lastControlCode_ = null;\n }\n\n char0 = data >>> 8;\n char1 = data & 0xff;\n\n if (data === this.PADDING_) {\n return;\n } else if (data === this.RESUME_CAPTION_LOADING_) {\n this.mode_ = 'popOn';\n } else if (data === this.END_OF_CAPTION_) {\n // If an EOC is received while in paint-on mode, the displayed caption\n // text should be swapped to non-displayed memory as if it was a pop-on\n // caption. Because of that, we should explicitly switch back to pop-on\n // mode\n this.mode_ = 'popOn';\n this.clearFormatting(packet.pts); // if a caption was being displayed, it's gone now\n\n this.flushDisplayed(packet.pts); // flip memory\n\n swap = this.displayed_;\n this.displayed_ = this.nonDisplayed_;\n this.nonDisplayed_ = swap; // start measuring the time to display the caption\n\n this.startPts_ = packet.pts;\n } else if (data === this.ROLL_UP_2_ROWS_) {\n this.rollUpRows_ = 2;\n this.setRollUp(packet.pts);\n } else if (data === this.ROLL_UP_3_ROWS_) {\n this.rollUpRows_ = 3;\n this.setRollUp(packet.pts);\n } else if (data === this.ROLL_UP_4_ROWS_) {\n this.rollUpRows_ = 4;\n this.setRollUp(packet.pts);\n } else if (data === this.CARRIAGE_RETURN_) {\n this.clearFormatting(packet.pts);\n this.flushDisplayed(packet.pts);\n this.shiftRowsUp_();\n this.startPts_ = packet.pts;\n } else if (data === this.BACKSPACE_) {\n if (this.mode_ === 'popOn') {\n this.nonDisplayed_[this.row_].text = this.nonDisplayed_[this.row_].text.slice(0, -1);\n } else {\n this.displayed_[this.row_].text = this.displayed_[this.row_].text.slice(0, -1);\n }\n } else if (data === this.ERASE_DISPLAYED_MEMORY_) {\n this.flushDisplayed(packet.pts);\n this.displayed_ = createDisplayBuffer();\n } else if (data === this.ERASE_NON_DISPLAYED_MEMORY_) {\n this.nonDisplayed_ = createDisplayBuffer();\n } else if (data === this.RESUME_DIRECT_CAPTIONING_) {\n if (this.mode_ !== 'paintOn') {\n // NOTE: This should be removed when proper caption positioning is\n // implemented\n this.flushDisplayed(packet.pts);\n this.displayed_ = createDisplayBuffer();\n }\n\n this.mode_ = 'paintOn';\n this.startPts_ = packet.pts; // Append special characters to caption text\n } else if (this.isSpecialCharacter(char0, char1)) {\n // Bitmask char0 so that we can apply character transformations\n // regardless of field and data channel.\n // Then byte-shift to the left and OR with char1 so we can pass the\n // entire character code to `getCharFromCode`.\n char0 = (char0 & 0x03) << 8;\n text = getCharFromCode(char0 | char1);\n this[this.mode_](packet.pts, text);\n this.column_++; // Append extended characters to caption text\n } else if (this.isExtCharacter(char0, char1)) {\n // Extended characters always follow their \"non-extended\" equivalents.\n // IE if a \"è\" is desired, you'll always receive \"eè\"; non-compliant\n // decoders are supposed to drop the \"è\", while compliant decoders\n // backspace the \"e\" and insert \"è\".\n // Delete the previous character\n if (this.mode_ === 'popOn') {\n this.nonDisplayed_[this.row_].text = this.nonDisplayed_[this.row_].text.slice(0, -1);\n } else {\n this.displayed_[this.row_].text = this.displayed_[this.row_].text.slice(0, -1);\n } // Bitmask char0 so that we can apply character transformations\n // regardless of field and data channel.\n // Then byte-shift to the left and OR with char1 so we can pass the\n // entire character code to `getCharFromCode`.\n\n\n char0 = (char0 & 0x03) << 8;\n text = getCharFromCode(char0 | char1);\n this[this.mode_](packet.pts, text);\n this.column_++; // Process mid-row codes\n } else if (this.isMidRowCode(char0, char1)) {\n // Attributes are not additive, so clear all formatting\n this.clearFormatting(packet.pts); // According to the standard, mid-row codes\n // should be replaced with spaces, so add one now\n\n this[this.mode_](packet.pts, ' ');\n this.column_++;\n\n if ((char1 & 0xe) === 0xe) {\n this.addFormatting(packet.pts, ['i']);\n }\n\n if ((char1 & 0x1) === 0x1) {\n this.addFormatting(packet.pts, ['u']);\n } // Detect offset control codes and adjust cursor\n\n } else if (this.isOffsetControlCode(char0, char1)) {\n // Cursor position is set by indent PAC (see below) in 4-column\n // increments, with an additional offset code of 1-3 to reach any\n // of the 32 columns specified by CEA-608. So all we need to do\n // here is increment the column cursor by the given offset.\n const offset = char1 & 0x03; // For an offest value 1-3, set the offset for that caption\n // in the non-displayed array.\n\n this.nonDisplayed_[this.row_].offset = offset;\n this.column_ += offset; // Detect PACs (Preamble Address Codes)\n } else if (this.isPAC(char0, char1)) {\n // There's no logic for PAC -> row mapping, so we have to just\n // find the row code in an array and use its index :(\n var row = ROWS.indexOf(data & 0x1f20); // Configure the caption window if we're in roll-up mode\n\n if (this.mode_ === 'rollUp') {\n // This implies that the base row is incorrectly set.\n // As per the recommendation in CEA-608(Base Row Implementation), defer to the number\n // of roll-up rows set.\n if (row - this.rollUpRows_ + 1 < 0) {\n row = this.rollUpRows_ - 1;\n }\n\n this.setRollUp(packet.pts, row);\n } // Ensure the row is between 0 and 14, otherwise use the most\n // recent or default row.\n\n\n if (row !== this.row_ && row >= 0 && row <= 14) {\n // formatting is only persistent for current row\n this.clearFormatting(packet.pts);\n this.row_ = row;\n } // All PACs can apply underline, so detect and apply\n // (All odd-numbered second bytes set underline)\n\n\n if (char1 & 0x1 && this.formatting_.indexOf('u') === -1) {\n this.addFormatting(packet.pts, ['u']);\n }\n\n if ((data & 0x10) === 0x10) {\n // We've got an indent level code. Each successive even number\n // increments the column cursor by 4, so we can get the desired\n // column position by bit-shifting to the right (to get n/2)\n // and multiplying by 4.\n const indentations = (data & 0xe) >> 1;\n this.column_ = indentations * 4; // add to the number of indentations for positioning\n\n this.nonDisplayed_[this.row_].indent += indentations;\n }\n\n if (this.isColorPAC(char1)) {\n // it's a color code, though we only support white, which\n // can be either normal or italicized. white italics can be\n // either 0x4e or 0x6e depending on the row, so we just\n // bitwise-and with 0xe to see if italics should be turned on\n if ((char1 & 0xe) === 0xe) {\n this.addFormatting(packet.pts, ['i']);\n }\n } // We have a normal character in char0, and possibly one in char1\n\n } else if (this.isNormalChar(char0)) {\n if (char1 === 0x00) {\n char1 = null;\n }\n\n text = getCharFromCode(char0);\n text += getCharFromCode(char1);\n this[this.mode_](packet.pts, text);\n this.column_ += text.length;\n } // finish data processing\n\n };\n };\n\n Cea608Stream.prototype = new Stream$7(); // Trigger a cue point that captures the current state of the\n // display buffer\n\n Cea608Stream.prototype.flushDisplayed = function (pts) {\n const logWarning = index => {\n this.trigger('log', {\n level: 'warn',\n message: 'Skipping a malformed 608 caption at index ' + index + '.'\n });\n };\n\n const content = [];\n this.displayed_.forEach((row, i) => {\n if (row && row.text && row.text.length) {\n try {\n // remove spaces from the start and end of the string\n row.text = row.text.trim();\n } catch (e) {\n // Ordinarily, this shouldn't happen. However, caption\n // parsing errors should not throw exceptions and\n // break playback.\n logWarning(i);\n } // See the below link for more details on the following fields:\n // https://dvcs.w3.org/hg/text-tracks/raw-file/default/608toVTT/608toVTT.html#positioning-in-cea-608\n\n\n if (row.text.length) {\n content.push({\n // The text to be displayed in the caption from this specific row, with whitespace removed.\n text: row.text,\n // Value between 1 and 15 representing the PAC row used to calculate line height.\n line: i + 1,\n // A number representing the indent position by percentage (CEA-608 PAC indent code).\n // The value will be a number between 10 and 80. Offset is used to add an aditional\n // value to the position if necessary.\n position: 10 + Math.min(70, row.indent * 10) + row.offset * 2.5\n });\n }\n } else if (row === undefined || row === null) {\n logWarning(i);\n }\n });\n\n if (content.length) {\n this.trigger('data', {\n startPts: this.startPts_,\n endPts: pts,\n content,\n stream: this.name_\n });\n }\n };\n /**\n * Zero out the data, used for startup and on seek\n */\n\n\n Cea608Stream.prototype.reset = function () {\n this.mode_ = 'popOn'; // When in roll-up mode, the index of the last row that will\n // actually display captions. If a caption is shifted to a row\n // with a lower index than this, it is cleared from the display\n // buffer\n\n this.topRow_ = 0;\n this.startPts_ = 0;\n this.displayed_ = createDisplayBuffer();\n this.nonDisplayed_ = createDisplayBuffer();\n this.lastControlCode_ = null; // Track row and column for proper line-breaking and spacing\n\n this.column_ = 0;\n this.row_ = BOTTOM_ROW;\n this.rollUpRows_ = 2; // This variable holds currently-applied formatting\n\n this.formatting_ = [];\n };\n /**\n * Sets up control code and related constants for this instance\n */\n\n\n Cea608Stream.prototype.setConstants = function () {\n // The following attributes have these uses:\n // ext_ : char0 for mid-row codes, and the base for extended\n // chars (ext_+0, ext_+1, and ext_+2 are char0s for\n // extended codes)\n // control_: char0 for control codes, except byte-shifted to the\n // left so that we can do this.control_ | CONTROL_CODE\n // offset_: char0 for tab offset codes\n //\n // It's also worth noting that control codes, and _only_ control codes,\n // differ between field 1 and field2. Field 2 control codes are always\n // their field 1 value plus 1. That's why there's the \"| field\" on the\n // control value.\n if (this.dataChannel_ === 0) {\n this.BASE_ = 0x10;\n this.EXT_ = 0x11;\n this.CONTROL_ = (0x14 | this.field_) << 8;\n this.OFFSET_ = 0x17;\n } else if (this.dataChannel_ === 1) {\n this.BASE_ = 0x18;\n this.EXT_ = 0x19;\n this.CONTROL_ = (0x1c | this.field_) << 8;\n this.OFFSET_ = 0x1f;\n } // Constants for the LSByte command codes recognized by Cea608Stream. This\n // list is not exhaustive. For a more comprehensive listing and semantics see\n // http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf\n // Padding\n\n\n this.PADDING_ = 0x0000; // Pop-on Mode\n\n this.RESUME_CAPTION_LOADING_ = this.CONTROL_ | 0x20;\n this.END_OF_CAPTION_ = this.CONTROL_ | 0x2f; // Roll-up Mode\n\n this.ROLL_UP_2_ROWS_ = this.CONTROL_ | 0x25;\n this.ROLL_UP_3_ROWS_ = this.CONTROL_ | 0x26;\n this.ROLL_UP_4_ROWS_ = this.CONTROL_ | 0x27;\n this.CARRIAGE_RETURN_ = this.CONTROL_ | 0x2d; // paint-on mode\n\n this.RESUME_DIRECT_CAPTIONING_ = this.CONTROL_ | 0x29; // Erasure\n\n this.BACKSPACE_ = this.CONTROL_ | 0x21;\n this.ERASE_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2c;\n this.ERASE_NON_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2e;\n };\n /**\n * Detects if the 2-byte packet data is a special character\n *\n * Special characters have a second byte in the range 0x30 to 0x3f,\n * with the first byte being 0x11 (for data channel 1) or 0x19 (for\n * data channel 2).\n *\n * @param {Integer} char0 The first byte\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the 2 bytes are an special character\n */\n\n\n Cea608Stream.prototype.isSpecialCharacter = function (char0, char1) {\n return char0 === this.EXT_ && char1 >= 0x30 && char1 <= 0x3f;\n };\n /**\n * Detects if the 2-byte packet data is an extended character\n *\n * Extended characters have a second byte in the range 0x20 to 0x3f,\n * with the first byte being 0x12 or 0x13 (for data channel 1) or\n * 0x1a or 0x1b (for data channel 2).\n *\n * @param {Integer} char0 The first byte\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the 2 bytes are an extended character\n */\n\n\n Cea608Stream.prototype.isExtCharacter = function (char0, char1) {\n return (char0 === this.EXT_ + 1 || char0 === this.EXT_ + 2) && char1 >= 0x20 && char1 <= 0x3f;\n };\n /**\n * Detects if the 2-byte packet is a mid-row code\n *\n * Mid-row codes have a second byte in the range 0x20 to 0x2f, with\n * the first byte being 0x11 (for data channel 1) or 0x19 (for data\n * channel 2).\n *\n * @param {Integer} char0 The first byte\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the 2 bytes are a mid-row code\n */\n\n\n Cea608Stream.prototype.isMidRowCode = function (char0, char1) {\n return char0 === this.EXT_ && char1 >= 0x20 && char1 <= 0x2f;\n };\n /**\n * Detects if the 2-byte packet is an offset control code\n *\n * Offset control codes have a second byte in the range 0x21 to 0x23,\n * with the first byte being 0x17 (for data channel 1) or 0x1f (for\n * data channel 2).\n *\n * @param {Integer} char0 The first byte\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the 2 bytes are an offset control code\n */\n\n\n Cea608Stream.prototype.isOffsetControlCode = function (char0, char1) {\n return char0 === this.OFFSET_ && char1 >= 0x21 && char1 <= 0x23;\n };\n /**\n * Detects if the 2-byte packet is a Preamble Address Code\n *\n * PACs have a first byte in the range 0x10 to 0x17 (for data channel 1)\n * or 0x18 to 0x1f (for data channel 2), with the second byte in the\n * range 0x40 to 0x7f.\n *\n * @param {Integer} char0 The first byte\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the 2 bytes are a PAC\n */\n\n\n Cea608Stream.prototype.isPAC = function (char0, char1) {\n return char0 >= this.BASE_ && char0 < this.BASE_ + 8 && char1 >= 0x40 && char1 <= 0x7f;\n };\n /**\n * Detects if a packet's second byte is in the range of a PAC color code\n *\n * PAC color codes have the second byte be in the range 0x40 to 0x4f, or\n * 0x60 to 0x6f.\n *\n * @param {Integer} char1 The second byte\n * @return {Boolean} Whether the byte is a color PAC\n */\n\n\n Cea608Stream.prototype.isColorPAC = function (char1) {\n return char1 >= 0x40 && char1 <= 0x4f || char1 >= 0x60 && char1 <= 0x7f;\n };\n /**\n * Detects if a single byte is in the range of a normal character\n *\n * Normal text bytes are in the range 0x20 to 0x7f.\n *\n * @param {Integer} char The byte\n * @return {Boolean} Whether the byte is a normal character\n */\n\n\n Cea608Stream.prototype.isNormalChar = function (char) {\n return char >= 0x20 && char <= 0x7f;\n };\n /**\n * Configures roll-up\n *\n * @param {Integer} pts Current PTS\n * @param {Integer} newBaseRow Used by PACs to slide the current window to\n * a new position\n */\n\n\n Cea608Stream.prototype.setRollUp = function (pts, newBaseRow) {\n // Reset the base row to the bottom row when switching modes\n if (this.mode_ !== 'rollUp') {\n this.row_ = BOTTOM_ROW;\n this.mode_ = 'rollUp'; // Spec says to wipe memories when switching to roll-up\n\n this.flushDisplayed(pts);\n this.nonDisplayed_ = createDisplayBuffer();\n this.displayed_ = createDisplayBuffer();\n }\n\n if (newBaseRow !== undefined && newBaseRow !== this.row_) {\n // move currently displayed captions (up or down) to the new base row\n for (var i = 0; i < this.rollUpRows_; i++) {\n this.displayed_[newBaseRow - i] = this.displayed_[this.row_ - i];\n this.displayed_[this.row_ - i] = {\n text: '',\n indent: 0,\n offset: 0\n };\n }\n }\n\n if (newBaseRow === undefined) {\n newBaseRow = this.row_;\n }\n\n this.topRow_ = newBaseRow - this.rollUpRows_ + 1;\n }; // Adds the opening HTML tag for the passed character to the caption text,\n // and keeps track of it for later closing\n\n\n Cea608Stream.prototype.addFormatting = function (pts, format) {\n this.formatting_ = this.formatting_.concat(format);\n var text = format.reduce(function (text, format) {\n return text + '<' + format + '>';\n }, '');\n this[this.mode_](pts, text);\n }; // Adds HTML closing tags for current formatting to caption text and\n // clears remembered formatting\n\n\n Cea608Stream.prototype.clearFormatting = function (pts) {\n if (!this.formatting_.length) {\n return;\n }\n\n var text = this.formatting_.reverse().reduce(function (text, format) {\n return text + '';\n }, '');\n this.formatting_ = [];\n this[this.mode_](pts, text);\n }; // Mode Implementations\n\n\n Cea608Stream.prototype.popOn = function (pts, text) {\n var baseRow = this.nonDisplayed_[this.row_].text; // buffer characters\n\n baseRow += text;\n this.nonDisplayed_[this.row_].text = baseRow;\n };\n\n Cea608Stream.prototype.rollUp = function (pts, text) {\n var baseRow = this.displayed_[this.row_].text;\n baseRow += text;\n this.displayed_[this.row_].text = baseRow;\n };\n\n Cea608Stream.prototype.shiftRowsUp_ = function () {\n var i; // clear out inactive rows\n\n for (i = 0; i < this.topRow_; i++) {\n this.displayed_[i] = {\n text: '',\n indent: 0,\n offset: 0\n };\n }\n\n for (i = this.row_ + 1; i < BOTTOM_ROW + 1; i++) {\n this.displayed_[i] = {\n text: '',\n indent: 0,\n offset: 0\n };\n } // shift displayed rows up\n\n\n for (i = this.topRow_; i < this.row_; i++) {\n this.displayed_[i] = this.displayed_[i + 1];\n } // clear out the bottom row\n\n\n this.displayed_[this.row_] = {\n text: '',\n indent: 0,\n offset: 0\n };\n };\n\n Cea608Stream.prototype.paintOn = function (pts, text) {\n var baseRow = this.displayed_[this.row_].text;\n baseRow += text;\n this.displayed_[this.row_].text = baseRow;\n }; // exports\n\n\n var captionStream = {\n CaptionStream: CaptionStream$2,\n Cea608Stream: Cea608Stream,\n Cea708Stream: Cea708Stream\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var streamTypes = {\n H264_STREAM_TYPE: 0x1B,\n ADTS_STREAM_TYPE: 0x0F,\n METADATA_STREAM_TYPE: 0x15\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Accepts program elementary stream (PES) data events and corrects\n * decode and presentation time stamps to account for a rollover\n * of the 33 bit value.\n */\n\n var Stream$6 = stream;\n var MAX_TS = 8589934592;\n var RO_THRESH = 4294967296;\n var TYPE_SHARED = 'shared';\n\n var handleRollover$1 = function (value, reference) {\n var direction = 1;\n\n if (value > reference) {\n // If the current timestamp value is greater than our reference timestamp and we detect a\n // timestamp rollover, this means the roll over is happening in the opposite direction.\n // Example scenario: Enter a long stream/video just after a rollover occurred. The reference\n // point will be set to a small number, e.g. 1. The user then seeks backwards over the\n // rollover point. In loading this segment, the timestamp values will be very large,\n // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust\n // the time stamp to be `value - 2^33`.\n direction = -1;\n } // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will\n // cause an incorrect adjustment.\n\n\n while (Math.abs(reference - value) > RO_THRESH) {\n value += direction * MAX_TS;\n }\n\n return value;\n };\n\n var TimestampRolloverStream$1 = function (type) {\n var lastDTS, referenceDTS;\n TimestampRolloverStream$1.prototype.init.call(this); // The \"shared\" type is used in cases where a stream will contain muxed\n // video and audio. We could use `undefined` here, but having a string\n // makes debugging a little clearer.\n\n this.type_ = type || TYPE_SHARED;\n\n this.push = function (data) {\n /**\n * Rollover stream expects data from elementary stream.\n * Elementary stream can push forward 2 types of data\n * - Parsed Video/Audio/Timed-metadata PES (packetized elementary stream) packets\n * - Tracks metadata from PMT (Program Map Table)\n * Rollover stream expects pts/dts info to be available, since it stores lastDTS\n * We should ignore non-PES packets since they may override lastDTS to undefined.\n * lastDTS is important to signal the next segments\n * about rollover from the previous segments.\n */\n if (data.type === 'metadata') {\n this.trigger('data', data);\n return;\n } // Any \"shared\" rollover streams will accept _all_ data. Otherwise,\n // streams will only accept data that matches their type.\n\n\n if (this.type_ !== TYPE_SHARED && data.type !== this.type_) {\n return;\n }\n\n if (referenceDTS === undefined) {\n referenceDTS = data.dts;\n }\n\n data.dts = handleRollover$1(data.dts, referenceDTS);\n data.pts = handleRollover$1(data.pts, referenceDTS);\n lastDTS = data.dts;\n this.trigger('data', data);\n };\n\n this.flush = function () {\n referenceDTS = lastDTS;\n this.trigger('done');\n };\n\n this.endTimeline = function () {\n this.flush();\n this.trigger('endedtimeline');\n };\n\n this.discontinuity = function () {\n referenceDTS = void 0;\n lastDTS = void 0;\n };\n\n this.reset = function () {\n this.discontinuity();\n this.trigger('reset');\n };\n };\n\n TimestampRolloverStream$1.prototype = new Stream$6();\n var timestampRolloverStream = {\n TimestampRolloverStream: TimestampRolloverStream$1,\n handleRollover: handleRollover$1\n }; // Once IE11 support is dropped, this function should be removed.\n\n var typedArrayIndexOf$1 = (typedArray, element, fromIndex) => {\n if (!typedArray) {\n return -1;\n }\n\n var currentIndex = fromIndex;\n\n for (; currentIndex < typedArray.length; currentIndex++) {\n if (typedArray[currentIndex] === element) {\n return currentIndex;\n }\n }\n\n return -1;\n };\n\n var typedArray = {\n typedArrayIndexOf: typedArrayIndexOf$1\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Tools for parsing ID3 frame data\n * @see http://id3.org/id3v2.3.0\n */\n\n var typedArrayIndexOf = typedArray.typedArrayIndexOf,\n // Frames that allow different types of text encoding contain a text\n // encoding description byte [ID3v2.4.0 section 4.]\n textEncodingDescriptionByte = {\n Iso88591: 0x00,\n // ISO-8859-1, terminated with \\0.\n Utf16: 0x01,\n // UTF-16 encoded Unicode BOM, terminated with \\0\\0\n Utf16be: 0x02,\n // UTF-16BE encoded Unicode, without BOM, terminated with \\0\\0\n Utf8: 0x03 // UTF-8 encoded Unicode, terminated with \\0\n\n },\n // return a percent-encoded representation of the specified byte range\n // @see http://en.wikipedia.org/wiki/Percent-encoding \n percentEncode$1 = function (bytes, start, end) {\n var i,\n result = '';\n\n for (i = start; i < end; i++) {\n result += '%' + ('00' + bytes[i].toString(16)).slice(-2);\n }\n\n return result;\n },\n // return the string representation of the specified byte range,\n // interpreted as UTf-8.\n parseUtf8 = function (bytes, start, end) {\n return decodeURIComponent(percentEncode$1(bytes, start, end));\n },\n // return the string representation of the specified byte range,\n // interpreted as ISO-8859-1.\n parseIso88591$1 = function (bytes, start, end) {\n return unescape(percentEncode$1(bytes, start, end)); // jshint ignore:line\n },\n parseSyncSafeInteger$1 = function (data) {\n return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];\n },\n frameParsers = {\n 'APIC': function (frame) {\n var i = 1,\n mimeTypeEndIndex,\n descriptionEndIndex,\n LINK_MIME_TYPE = '-->';\n\n if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {\n // ignore frames with unrecognized character encodings\n return;\n } // parsing fields [ID3v2.4.0 section 4.14.]\n\n\n mimeTypeEndIndex = typedArrayIndexOf(frame.data, 0, i);\n\n if (mimeTypeEndIndex < 0) {\n // malformed frame\n return;\n } // parsing Mime type field (terminated with \\0)\n\n\n frame.mimeType = parseIso88591$1(frame.data, i, mimeTypeEndIndex);\n i = mimeTypeEndIndex + 1; // parsing 1-byte Picture Type field\n\n frame.pictureType = frame.data[i];\n i++;\n descriptionEndIndex = typedArrayIndexOf(frame.data, 0, i);\n\n if (descriptionEndIndex < 0) {\n // malformed frame\n return;\n } // parsing Description field (terminated with \\0)\n\n\n frame.description = parseUtf8(frame.data, i, descriptionEndIndex);\n i = descriptionEndIndex + 1;\n\n if (frame.mimeType === LINK_MIME_TYPE) {\n // parsing Picture Data field as URL (always represented as ISO-8859-1 [ID3v2.4.0 section 4.])\n frame.url = parseIso88591$1(frame.data, i, frame.data.length);\n } else {\n // parsing Picture Data field as binary data\n frame.pictureData = frame.data.subarray(i, frame.data.length);\n }\n },\n 'T*': function (frame) {\n if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {\n // ignore frames with unrecognized character encodings\n return;\n } // parse text field, do not include null terminator in the frame value\n // frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]\n\n\n frame.value = parseUtf8(frame.data, 1, frame.data.length).replace(/\\0*$/, ''); // text information frames supports multiple strings, stored as a terminator separated list [ID3v2.4.0 section 4.2.]\n\n frame.values = frame.value.split('\\0');\n },\n 'TXXX': function (frame) {\n var descriptionEndIndex;\n\n if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {\n // ignore frames with unrecognized character encodings\n return;\n }\n\n descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);\n\n if (descriptionEndIndex === -1) {\n return;\n } // parse the text fields\n\n\n frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // do not include the null terminator in the tag value\n // frames that allow different types of encoding contain terminated text\n // [ID3v2.4.0 section 4.]\n\n frame.value = parseUtf8(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\\0*$/, '');\n frame.data = frame.value;\n },\n 'W*': function (frame) {\n // parse URL field; URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]\n // if the value is followed by a string termination all the following information should be ignored [ID3v2.4.0 section 4.3]\n frame.url = parseIso88591$1(frame.data, 0, frame.data.length).replace(/\\0.*$/, '');\n },\n 'WXXX': function (frame) {\n var descriptionEndIndex;\n\n if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {\n // ignore frames with unrecognized character encodings\n return;\n }\n\n descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);\n\n if (descriptionEndIndex === -1) {\n return;\n } // parse the description and URL fields\n\n\n frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]\n // if the value is followed by a string termination all the following information\n // should be ignored [ID3v2.4.0 section 4.3]\n\n frame.url = parseIso88591$1(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\\0.*$/, '');\n },\n 'PRIV': function (frame) {\n var i;\n\n for (i = 0; i < frame.data.length; i++) {\n if (frame.data[i] === 0) {\n // parse the description and URL fields\n frame.owner = parseIso88591$1(frame.data, 0, i);\n break;\n }\n }\n\n frame.privateData = frame.data.subarray(i + 1);\n frame.data = frame.privateData;\n }\n };\n\n var parseId3Frames$1 = function (data) {\n var frameSize,\n frameHeader,\n frameStart = 10,\n tagSize = 0,\n frames = []; // If we don't have enough data for a header, 10 bytes, \n // or 'ID3' in the first 3 bytes this is not a valid ID3 tag.\n\n if (data.length < 10 || data[0] !== 'I'.charCodeAt(0) || data[1] !== 'D'.charCodeAt(0) || data[2] !== '3'.charCodeAt(0)) {\n return;\n } // the frame size is transmitted as a 28-bit integer in the\n // last four bytes of the ID3 header.\n // The most significant bit of each byte is dropped and the\n // results concatenated to recover the actual value.\n\n\n tagSize = parseSyncSafeInteger$1(data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more\n // convenient for our comparisons to include it\n\n tagSize += 10; // check bit 6 of byte 5 for the extended header flag.\n\n var hasExtendedHeader = data[5] & 0x40;\n\n if (hasExtendedHeader) {\n // advance the frame start past the extended header\n frameStart += 4; // header size field\n\n frameStart += parseSyncSafeInteger$1(data.subarray(10, 14));\n tagSize -= parseSyncSafeInteger$1(data.subarray(16, 20)); // clip any padding off the end\n } // parse one or more ID3 frames\n // http://id3.org/id3v2.3.0#ID3v2_frame_overview\n\n\n do {\n // determine the number of bytes in this frame\n frameSize = parseSyncSafeInteger$1(data.subarray(frameStart + 4, frameStart + 8));\n\n if (frameSize < 1) {\n break;\n }\n\n frameHeader = String.fromCharCode(data[frameStart], data[frameStart + 1], data[frameStart + 2], data[frameStart + 3]);\n var frame = {\n id: frameHeader,\n data: data.subarray(frameStart + 10, frameStart + frameSize + 10)\n };\n frame.key = frame.id; // parse frame values\n\n if (frameParsers[frame.id]) {\n // use frame specific parser\n frameParsers[frame.id](frame);\n } else if (frame.id[0] === 'T') {\n // use text frame generic parser\n frameParsers['T*'](frame);\n } else if (frame.id[0] === 'W') {\n // use URL link frame generic parser\n frameParsers['W*'](frame);\n }\n\n frames.push(frame);\n frameStart += 10; // advance past the frame header\n\n frameStart += frameSize; // advance past the frame body\n } while (frameStart < tagSize);\n\n return frames;\n };\n\n var parseId3 = {\n parseId3Frames: parseId3Frames$1,\n parseSyncSafeInteger: parseSyncSafeInteger$1,\n frameParsers: frameParsers\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Accepts program elementary stream (PES) data events and parses out\n * ID3 metadata from them, if present.\n * @see http://id3.org/id3v2.3.0\n */\n\n var Stream$5 = stream,\n StreamTypes$3 = streamTypes,\n id3 = parseId3,\n MetadataStream;\n\n MetadataStream = function (options) {\n var settings = {\n // the bytes of the program-level descriptor field in MP2T\n // see ISO/IEC 13818-1:2013 (E), section 2.6 \"Program and\n // program element descriptors\"\n descriptor: options && options.descriptor\n },\n // the total size in bytes of the ID3 tag being parsed\n tagSize = 0,\n // tag data that is not complete enough to be parsed\n buffer = [],\n // the total number of bytes currently in the buffer\n bufferSize = 0,\n i;\n MetadataStream.prototype.init.call(this); // calculate the text track in-band metadata track dispatch type\n // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track\n\n this.dispatchType = StreamTypes$3.METADATA_STREAM_TYPE.toString(16);\n\n if (settings.descriptor) {\n for (i = 0; i < settings.descriptor.length; i++) {\n this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2);\n }\n }\n\n this.push = function (chunk) {\n var tag, frameStart, frameSize, frame, i, frameHeader;\n\n if (chunk.type !== 'timed-metadata') {\n return;\n } // if data_alignment_indicator is set in the PES header,\n // we must have the start of a new ID3 tag. Assume anything\n // remaining in the buffer was malformed and throw it out\n\n\n if (chunk.dataAlignmentIndicator) {\n bufferSize = 0;\n buffer.length = 0;\n } // ignore events that don't look like ID3 data\n\n\n if (buffer.length === 0 && (chunk.data.length < 10 || chunk.data[0] !== 'I'.charCodeAt(0) || chunk.data[1] !== 'D'.charCodeAt(0) || chunk.data[2] !== '3'.charCodeAt(0))) {\n this.trigger('log', {\n level: 'warn',\n message: 'Skipping unrecognized metadata packet'\n });\n return;\n } // add this chunk to the data we've collected so far\n\n\n buffer.push(chunk);\n bufferSize += chunk.data.byteLength; // grab the size of the entire frame from the ID3 header\n\n if (buffer.length === 1) {\n // the frame size is transmitted as a 28-bit integer in the\n // last four bytes of the ID3 header.\n // The most significant bit of each byte is dropped and the\n // results concatenated to recover the actual value.\n tagSize = id3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more\n // convenient for our comparisons to include it\n\n tagSize += 10;\n } // if the entire frame has not arrived, wait for more data\n\n\n if (bufferSize < tagSize) {\n return;\n } // collect the entire frame so it can be parsed\n\n\n tag = {\n data: new Uint8Array(tagSize),\n frames: [],\n pts: buffer[0].pts,\n dts: buffer[0].dts\n };\n\n for (i = 0; i < tagSize;) {\n tag.data.set(buffer[0].data.subarray(0, tagSize - i), i);\n i += buffer[0].data.byteLength;\n bufferSize -= buffer[0].data.byteLength;\n buffer.shift();\n } // find the start of the first frame and the end of the tag\n\n\n frameStart = 10;\n\n if (tag.data[5] & 0x40) {\n // advance the frame start past the extended header\n frameStart += 4; // header size field\n\n frameStart += id3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end\n\n tagSize -= id3.parseSyncSafeInteger(tag.data.subarray(16, 20));\n } // parse one or more ID3 frames\n // http://id3.org/id3v2.3.0#ID3v2_frame_overview\n\n\n do {\n // determine the number of bytes in this frame\n frameSize = id3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));\n\n if (frameSize < 1) {\n this.trigger('log', {\n level: 'warn',\n message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'\n }); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames\n // to be sent along.\n\n break;\n }\n\n frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);\n frame = {\n id: frameHeader,\n data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)\n };\n frame.key = frame.id; // parse frame values\n\n if (id3.frameParsers[frame.id]) {\n // use frame specific parser\n id3.frameParsers[frame.id](frame);\n } else if (frame.id[0] === 'T') {\n // use text frame generic parser\n id3.frameParsers['T*'](frame);\n } else if (frame.id[0] === 'W') {\n // use URL link frame generic parser\n id3.frameParsers['W*'](frame);\n } // handle the special PRIV frame used to indicate the start\n // time for raw AAC data\n\n\n if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {\n var d = frame.data,\n size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;\n size *= 4;\n size += d[7] & 0x03;\n frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based\n // on the value of this frame\n // we couldn't have known the appropriate pts and dts before\n // parsing this ID3 tag so set those values now\n\n if (tag.pts === undefined && tag.dts === undefined) {\n tag.pts = frame.timeStamp;\n tag.dts = frame.timeStamp;\n }\n\n this.trigger('timestamp', frame);\n }\n\n tag.frames.push(frame);\n frameStart += 10; // advance past the frame header\n\n frameStart += frameSize; // advance past the frame body\n } while (frameStart < tagSize);\n\n this.trigger('data', tag);\n };\n };\n\n MetadataStream.prototype = new Stream$5();\n var metadataStream = MetadataStream;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * A stream-based mp2t to mp4 converter. This utility can be used to\n * deliver mp4s to a SourceBuffer on platforms that support native\n * Media Source Extensions.\n */\n\n var Stream$4 = stream,\n CaptionStream$1 = captionStream,\n StreamTypes$2 = streamTypes,\n TimestampRolloverStream = timestampRolloverStream.TimestampRolloverStream; // object types\n\n var TransportPacketStream, TransportParseStream, ElementaryStream; // constants\n\n var MP2T_PACKET_LENGTH$1 = 188,\n // bytes\n SYNC_BYTE$1 = 0x47;\n /**\n * Splits an incoming stream of binary data into MPEG-2 Transport\n * Stream packets.\n */\n\n TransportPacketStream = function () {\n var buffer = new Uint8Array(MP2T_PACKET_LENGTH$1),\n bytesInBuffer = 0;\n TransportPacketStream.prototype.init.call(this); // Deliver new bytes to the stream.\n\n /**\n * Split a stream of data into M2TS packets\n **/\n\n this.push = function (bytes) {\n var startIndex = 0,\n endIndex = MP2T_PACKET_LENGTH$1,\n everything; // If there are bytes remaining from the last segment, prepend them to the\n // bytes that were pushed in\n\n if (bytesInBuffer) {\n everything = new Uint8Array(bytes.byteLength + bytesInBuffer);\n everything.set(buffer.subarray(0, bytesInBuffer));\n everything.set(bytes, bytesInBuffer);\n bytesInBuffer = 0;\n } else {\n everything = bytes;\n } // While we have enough data for a packet\n\n\n while (endIndex < everything.byteLength) {\n // Look for a pair of start and end sync bytes in the data..\n if (everything[startIndex] === SYNC_BYTE$1 && everything[endIndex] === SYNC_BYTE$1) {\n // We found a packet so emit it and jump one whole packet forward in\n // the stream\n this.trigger('data', everything.subarray(startIndex, endIndex));\n startIndex += MP2T_PACKET_LENGTH$1;\n endIndex += MP2T_PACKET_LENGTH$1;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex++;\n endIndex++;\n } // If there was some data left over at the end of the segment that couldn't\n // possibly be a whole packet, keep it because it might be the start of a packet\n // that continues in the next segment\n\n\n if (startIndex < everything.byteLength) {\n buffer.set(everything.subarray(startIndex), 0);\n bytesInBuffer = everything.byteLength - startIndex;\n }\n };\n /**\n * Passes identified M2TS packets to the TransportParseStream to be parsed\n **/\n\n\n this.flush = function () {\n // If the buffer contains a whole packet when we are being flushed, emit it\n // and empty the buffer. Otherwise hold onto the data because it may be\n // important for decoding the next segment\n if (bytesInBuffer === MP2T_PACKET_LENGTH$1 && buffer[0] === SYNC_BYTE$1) {\n this.trigger('data', buffer);\n bytesInBuffer = 0;\n }\n\n this.trigger('done');\n };\n\n this.endTimeline = function () {\n this.flush();\n this.trigger('endedtimeline');\n };\n\n this.reset = function () {\n bytesInBuffer = 0;\n this.trigger('reset');\n };\n };\n\n TransportPacketStream.prototype = new Stream$4();\n /**\n * Accepts an MP2T TransportPacketStream and emits data events with parsed\n * forms of the individual transport stream packets.\n */\n\n TransportParseStream = function () {\n var parsePsi, parsePat, parsePmt, self;\n TransportParseStream.prototype.init.call(this);\n self = this;\n this.packetsWaitingForPmt = [];\n this.programMapTable = undefined;\n\n parsePsi = function (payload, psi) {\n var offset = 0; // PSI packets may be split into multiple sections and those\n // sections may be split into multiple packets. If a PSI\n // section starts in this packet, the payload_unit_start_indicator\n // will be true and the first byte of the payload will indicate\n // the offset from the current position to the start of the\n // section.\n\n if (psi.payloadUnitStartIndicator) {\n offset += payload[offset] + 1;\n }\n\n if (psi.type === 'pat') {\n parsePat(payload.subarray(offset), psi);\n } else {\n parsePmt(payload.subarray(offset), psi);\n }\n };\n\n parsePat = function (payload, pat) {\n pat.section_number = payload[7]; // eslint-disable-line camelcase\n\n pat.last_section_number = payload[8]; // eslint-disable-line camelcase\n // skip the PSI header and parse the first PMT entry\n\n self.pmtPid = (payload[10] & 0x1F) << 8 | payload[11];\n pat.pmtPid = self.pmtPid;\n };\n /**\n * Parse out the relevant fields of a Program Map Table (PMT).\n * @param payload {Uint8Array} the PMT-specific portion of an MP2T\n * packet. The first byte in this array should be the table_id\n * field.\n * @param pmt {object} the object that should be decorated with\n * fields parsed from the PMT.\n */\n\n\n parsePmt = function (payload, pmt) {\n var sectionLength, tableEnd, programInfoLength, offset; // PMTs can be sent ahead of the time when they should actually\n // take effect. We don't believe this should ever be the case\n // for HLS but we'll ignore \"forward\" PMT declarations if we see\n // them. Future PMT declarations have the current_next_indicator\n // set to zero.\n\n if (!(payload[5] & 0x01)) {\n return;\n } // overwrite any existing program map table\n\n\n self.programMapTable = {\n video: null,\n audio: null,\n 'timed-metadata': {}\n }; // the mapping table ends at the end of the current section\n\n sectionLength = (payload[1] & 0x0f) << 8 | payload[2];\n tableEnd = 3 + sectionLength - 4; // to determine where the table is, we have to figure out how\n // long the program info descriptors are\n\n programInfoLength = (payload[10] & 0x0f) << 8 | payload[11]; // advance the offset to the first entry in the mapping table\n\n offset = 12 + programInfoLength;\n\n while (offset < tableEnd) {\n var streamType = payload[offset];\n var pid = (payload[offset + 1] & 0x1F) << 8 | payload[offset + 2]; // only map a single elementary_pid for audio and video stream types\n // TODO: should this be done for metadata too? for now maintain behavior of\n // multiple metadata streams\n\n if (streamType === StreamTypes$2.H264_STREAM_TYPE && self.programMapTable.video === null) {\n self.programMapTable.video = pid;\n } else if (streamType === StreamTypes$2.ADTS_STREAM_TYPE && self.programMapTable.audio === null) {\n self.programMapTable.audio = pid;\n } else if (streamType === StreamTypes$2.METADATA_STREAM_TYPE) {\n // map pid to stream type for metadata streams\n self.programMapTable['timed-metadata'][pid] = streamType;\n } // move to the next table entry\n // skip past the elementary stream descriptors, if present\n\n\n offset += ((payload[offset + 3] & 0x0F) << 8 | payload[offset + 4]) + 5;\n } // record the map on the packet as well\n\n\n pmt.programMapTable = self.programMapTable;\n };\n /**\n * Deliver a new MP2T packet to the next stream in the pipeline.\n */\n\n\n this.push = function (packet) {\n var result = {},\n offset = 4;\n result.payloadUnitStartIndicator = !!(packet[1] & 0x40); // pid is a 13-bit field starting at the last bit of packet[1]\n\n result.pid = packet[1] & 0x1f;\n result.pid <<= 8;\n result.pid |= packet[2]; // if an adaption field is present, its length is specified by the\n // fifth byte of the TS packet header. The adaptation field is\n // used to add stuffing to PES packets that don't fill a complete\n // TS packet, and to specify some forms of timing and control data\n // that we do not currently use.\n\n if ((packet[3] & 0x30) >>> 4 > 0x01) {\n offset += packet[offset] + 1;\n } // parse the rest of the packet based on the type\n\n\n if (result.pid === 0) {\n result.type = 'pat';\n parsePsi(packet.subarray(offset), result);\n this.trigger('data', result);\n } else if (result.pid === this.pmtPid) {\n result.type = 'pmt';\n parsePsi(packet.subarray(offset), result);\n this.trigger('data', result); // if there are any packets waiting for a PMT to be found, process them now\n\n while (this.packetsWaitingForPmt.length) {\n this.processPes_.apply(this, this.packetsWaitingForPmt.shift());\n }\n } else if (this.programMapTable === undefined) {\n // When we have not seen a PMT yet, defer further processing of\n // PES packets until one has been parsed\n this.packetsWaitingForPmt.push([packet, offset, result]);\n } else {\n this.processPes_(packet, offset, result);\n }\n };\n\n this.processPes_ = function (packet, offset, result) {\n // set the appropriate stream type\n if (result.pid === this.programMapTable.video) {\n result.streamType = StreamTypes$2.H264_STREAM_TYPE;\n } else if (result.pid === this.programMapTable.audio) {\n result.streamType = StreamTypes$2.ADTS_STREAM_TYPE;\n } else {\n // if not video or audio, it is timed-metadata or unknown\n // if unknown, streamType will be undefined\n result.streamType = this.programMapTable['timed-metadata'][result.pid];\n }\n\n result.type = 'pes';\n result.data = packet.subarray(offset);\n this.trigger('data', result);\n };\n };\n\n TransportParseStream.prototype = new Stream$4();\n TransportParseStream.STREAM_TYPES = {\n h264: 0x1b,\n adts: 0x0f\n };\n /**\n * Reconsistutes program elementary stream (PES) packets from parsed\n * transport stream packets. That is, if you pipe an\n * mp2t.TransportParseStream into a mp2t.ElementaryStream, the output\n * events will be events which capture the bytes for individual PES\n * packets plus relevant metadata that has been extracted from the\n * container.\n */\n\n ElementaryStream = function () {\n var self = this,\n segmentHadPmt = false,\n // PES packet fragments\n video = {\n data: [],\n size: 0\n },\n audio = {\n data: [],\n size: 0\n },\n timedMetadata = {\n data: [],\n size: 0\n },\n programMapTable,\n parsePes = function (payload, pes) {\n var ptsDtsFlags;\n const startPrefix = payload[0] << 16 | payload[1] << 8 | payload[2]; // default to an empty array\n\n pes.data = new Uint8Array(); // In certain live streams, the start of a TS fragment has ts packets\n // that are frame data that is continuing from the previous fragment. This\n // is to check that the pes data is the start of a new pes payload\n\n if (startPrefix !== 1) {\n return;\n } // get the packet length, this will be 0 for video\n\n\n pes.packetLength = 6 + (payload[4] << 8 | payload[5]); // find out if this packets starts a new keyframe\n\n pes.dataAlignmentIndicator = (payload[6] & 0x04) !== 0; // PES packets may be annotated with a PTS value, or a PTS value\n // and a DTS value. Determine what combination of values is\n // available to work with.\n\n ptsDtsFlags = payload[7]; // PTS and DTS are normally stored as a 33-bit number. Javascript\n // performs all bitwise operations on 32-bit integers but javascript\n // supports a much greater range (52-bits) of integer using standard\n // mathematical operations.\n // We construct a 31-bit value using bitwise operators over the 31\n // most significant bits and then multiply by 4 (equal to a left-shift\n // of 2) before we add the final 2 least significant bits of the\n // timestamp (equal to an OR.)\n\n if (ptsDtsFlags & 0xC0) {\n // the PTS and DTS are not written out directly. For information\n // on how they are encoded, see\n // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html\n pes.pts = (payload[9] & 0x0E) << 27 | (payload[10] & 0xFF) << 20 | (payload[11] & 0xFE) << 12 | (payload[12] & 0xFF) << 5 | (payload[13] & 0xFE) >>> 3;\n pes.pts *= 4; // Left shift by 2\n\n pes.pts += (payload[13] & 0x06) >>> 1; // OR by the two LSBs\n\n pes.dts = pes.pts;\n\n if (ptsDtsFlags & 0x40) {\n pes.dts = (payload[14] & 0x0E) << 27 | (payload[15] & 0xFF) << 20 | (payload[16] & 0xFE) << 12 | (payload[17] & 0xFF) << 5 | (payload[18] & 0xFE) >>> 3;\n pes.dts *= 4; // Left shift by 2\n\n pes.dts += (payload[18] & 0x06) >>> 1; // OR by the two LSBs\n }\n } // the data section starts immediately after the PES header.\n // pes_header_data_length specifies the number of header bytes\n // that follow the last byte of the field.\n\n\n pes.data = payload.subarray(9 + payload[8]);\n },\n\n /**\n * Pass completely parsed PES packets to the next stream in the pipeline\n **/\n flushStream = function (stream, type, forceFlush) {\n var packetData = new Uint8Array(stream.size),\n event = {\n type: type\n },\n i = 0,\n offset = 0,\n packetFlushable = false,\n fragment; // do nothing if there is not enough buffered data for a complete\n // PES header\n\n if (!stream.data.length || stream.size < 9) {\n return;\n }\n\n event.trackId = stream.data[0].pid; // reassemble the packet\n\n for (i = 0; i < stream.data.length; i++) {\n fragment = stream.data[i];\n packetData.set(fragment.data, offset);\n offset += fragment.data.byteLength;\n } // parse assembled packet's PES header\n\n\n parsePes(packetData, event); // non-video PES packets MUST have a non-zero PES_packet_length\n // check that there is enough stream data to fill the packet\n\n packetFlushable = type === 'video' || event.packetLength <= stream.size; // flush pending packets if the conditions are right\n\n if (forceFlush || packetFlushable) {\n stream.size = 0;\n stream.data.length = 0;\n } // only emit packets that are complete. this is to avoid assembling\n // incomplete PES packets due to poor segmentation\n\n\n if (packetFlushable) {\n self.trigger('data', event);\n }\n };\n\n ElementaryStream.prototype.init.call(this);\n /**\n * Identifies M2TS packet types and parses PES packets using metadata\n * parsed from the PMT\n **/\n\n this.push = function (data) {\n ({\n pat: function () {// we have to wait for the PMT to arrive as well before we\n // have any meaningful metadata\n },\n pes: function () {\n var stream, streamType;\n\n switch (data.streamType) {\n case StreamTypes$2.H264_STREAM_TYPE:\n stream = video;\n streamType = 'video';\n break;\n\n case StreamTypes$2.ADTS_STREAM_TYPE:\n stream = audio;\n streamType = 'audio';\n break;\n\n case StreamTypes$2.METADATA_STREAM_TYPE:\n stream = timedMetadata;\n streamType = 'timed-metadata';\n break;\n\n default:\n // ignore unknown stream types\n return;\n } // if a new packet is starting, we can flush the completed\n // packet\n\n\n if (data.payloadUnitStartIndicator) {\n flushStream(stream, streamType, true);\n } // buffer this fragment until we are sure we've received the\n // complete payload\n\n\n stream.data.push(data);\n stream.size += data.data.byteLength;\n },\n pmt: function () {\n var event = {\n type: 'metadata',\n tracks: []\n };\n programMapTable = data.programMapTable; // translate audio and video streams to tracks\n\n if (programMapTable.video !== null) {\n event.tracks.push({\n timelineStartInfo: {\n baseMediaDecodeTime: 0\n },\n id: +programMapTable.video,\n codec: 'avc',\n type: 'video'\n });\n }\n\n if (programMapTable.audio !== null) {\n event.tracks.push({\n timelineStartInfo: {\n baseMediaDecodeTime: 0\n },\n id: +programMapTable.audio,\n codec: 'adts',\n type: 'audio'\n });\n }\n\n segmentHadPmt = true;\n self.trigger('data', event);\n }\n })[data.type]();\n };\n\n this.reset = function () {\n video.size = 0;\n video.data.length = 0;\n audio.size = 0;\n audio.data.length = 0;\n this.trigger('reset');\n };\n /**\n * Flush any remaining input. Video PES packets may be of variable\n * length. Normally, the start of a new video packet can trigger the\n * finalization of the previous packet. That is not possible if no\n * more video is forthcoming, however. In that case, some other\n * mechanism (like the end of the file) has to be employed. When it is\n * clear that no additional data is forthcoming, calling this method\n * will flush the buffered packets.\n */\n\n\n this.flushStreams_ = function () {\n // !!THIS ORDER IS IMPORTANT!!\n // video first then audio\n flushStream(video, 'video');\n flushStream(audio, 'audio');\n flushStream(timedMetadata, 'timed-metadata');\n };\n\n this.flush = function () {\n // if on flush we haven't had a pmt emitted\n // and we have a pmt to emit. emit the pmt\n // so that we trigger a trackinfo downstream.\n if (!segmentHadPmt && programMapTable) {\n var pmt = {\n type: 'metadata',\n tracks: []\n }; // translate audio and video streams to tracks\n\n if (programMapTable.video !== null) {\n pmt.tracks.push({\n timelineStartInfo: {\n baseMediaDecodeTime: 0\n },\n id: +programMapTable.video,\n codec: 'avc',\n type: 'video'\n });\n }\n\n if (programMapTable.audio !== null) {\n pmt.tracks.push({\n timelineStartInfo: {\n baseMediaDecodeTime: 0\n },\n id: +programMapTable.audio,\n codec: 'adts',\n type: 'audio'\n });\n }\n\n self.trigger('data', pmt);\n }\n\n segmentHadPmt = false;\n this.flushStreams_();\n this.trigger('done');\n };\n };\n\n ElementaryStream.prototype = new Stream$4();\n var m2ts$1 = {\n PAT_PID: 0x0000,\n MP2T_PACKET_LENGTH: MP2T_PACKET_LENGTH$1,\n TransportPacketStream: TransportPacketStream,\n TransportParseStream: TransportParseStream,\n ElementaryStream: ElementaryStream,\n TimestampRolloverStream: TimestampRolloverStream,\n CaptionStream: CaptionStream$1.CaptionStream,\n Cea608Stream: CaptionStream$1.Cea608Stream,\n Cea708Stream: CaptionStream$1.Cea708Stream,\n MetadataStream: metadataStream\n };\n\n for (var type in StreamTypes$2) {\n if (StreamTypes$2.hasOwnProperty(type)) {\n m2ts$1[type] = StreamTypes$2[type];\n }\n }\n\n var m2ts_1 = m2ts$1;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var Stream$3 = stream;\n var ONE_SECOND_IN_TS$2 = clock$2.ONE_SECOND_IN_TS;\n var AdtsStream$1;\n var ADTS_SAMPLING_FREQUENCIES$1 = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];\n /*\n * Accepts a ElementaryStream and emits data events with parsed\n * AAC Audio Frames of the individual packets. Input audio in ADTS\n * format is unpacked and re-emitted as AAC frames.\n *\n * @see http://wiki.multimedia.cx/index.php?title=ADTS\n * @see http://wiki.multimedia.cx/?title=Understanding_AAC\n */\n\n AdtsStream$1 = function (handlePartialSegments) {\n var buffer,\n frameNum = 0;\n AdtsStream$1.prototype.init.call(this);\n\n this.skipWarn_ = function (start, end) {\n this.trigger('log', {\n level: 'warn',\n message: `adts skiping bytes ${start} to ${end} in frame ${frameNum} outside syncword`\n });\n };\n\n this.push = function (packet) {\n var i = 0,\n frameLength,\n protectionSkipBytes,\n oldBuffer,\n sampleCount,\n adtsFrameDuration;\n\n if (!handlePartialSegments) {\n frameNum = 0;\n }\n\n if (packet.type !== 'audio') {\n // ignore non-audio data\n return;\n } // Prepend any data in the buffer to the input data so that we can parse\n // aac frames the cross a PES packet boundary\n\n\n if (buffer && buffer.length) {\n oldBuffer = buffer;\n buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);\n buffer.set(oldBuffer);\n buffer.set(packet.data, oldBuffer.byteLength);\n } else {\n buffer = packet.data;\n } // unpack any ADTS frames which have been fully received\n // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS\n\n\n var skip; // We use i + 7 here because we want to be able to parse the entire header.\n // If we don't have enough bytes to do that, then we definitely won't have a full frame.\n\n while (i + 7 < buffer.length) {\n // Look for the start of an ADTS header..\n if (buffer[i] !== 0xFF || (buffer[i + 1] & 0xF6) !== 0xF0) {\n if (typeof skip !== 'number') {\n skip = i;\n } // If a valid header was not found, jump one forward and attempt to\n // find a valid ADTS header starting at the next byte\n\n\n i++;\n continue;\n }\n\n if (typeof skip === 'number') {\n this.skipWarn_(skip, i);\n skip = null;\n } // The protection skip bit tells us if we have 2 bytes of CRC data at the\n // end of the ADTS header\n\n\n protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2; // Frame length is a 13 bit integer starting 16 bits from the\n // end of the sync sequence\n // NOTE: frame length includes the size of the header\n\n frameLength = (buffer[i + 3] & 0x03) << 11 | buffer[i + 4] << 3 | (buffer[i + 5] & 0xe0) >> 5;\n sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024;\n adtsFrameDuration = sampleCount * ONE_SECOND_IN_TS$2 / ADTS_SAMPLING_FREQUENCIES$1[(buffer[i + 2] & 0x3c) >>> 2]; // If we don't have enough data to actually finish this ADTS frame,\n // then we have to wait for more data\n\n if (buffer.byteLength - i < frameLength) {\n break;\n } // Otherwise, deliver the complete AAC frame\n\n\n this.trigger('data', {\n pts: packet.pts + frameNum * adtsFrameDuration,\n dts: packet.dts + frameNum * adtsFrameDuration,\n sampleCount: sampleCount,\n audioobjecttype: (buffer[i + 2] >>> 6 & 0x03) + 1,\n channelcount: (buffer[i + 2] & 1) << 2 | (buffer[i + 3] & 0xc0) >>> 6,\n samplerate: ADTS_SAMPLING_FREQUENCIES$1[(buffer[i + 2] & 0x3c) >>> 2],\n samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2,\n // assume ISO/IEC 14496-12 AudioSampleEntry default of 16\n samplesize: 16,\n // data is the frame without it's header\n data: buffer.subarray(i + 7 + protectionSkipBytes, i + frameLength)\n });\n frameNum++;\n i += frameLength;\n }\n\n if (typeof skip === 'number') {\n this.skipWarn_(skip, i);\n skip = null;\n } // remove processed bytes from the buffer.\n\n\n buffer = buffer.subarray(i);\n };\n\n this.flush = function () {\n frameNum = 0;\n this.trigger('done');\n };\n\n this.reset = function () {\n buffer = void 0;\n this.trigger('reset');\n };\n\n this.endTimeline = function () {\n buffer = void 0;\n this.trigger('endedtimeline');\n };\n };\n\n AdtsStream$1.prototype = new Stream$3();\n var adts = AdtsStream$1;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var ExpGolomb$1;\n /**\n * Parser for exponential Golomb codes, a variable-bitwidth number encoding\n * scheme used by h264.\n */\n\n ExpGolomb$1 = function (workingData) {\n var // the number of bytes left to examine in workingData\n workingBytesAvailable = workingData.byteLength,\n // the current word being examined\n workingWord = 0,\n // :uint\n // the number of bits left to examine in the current word\n workingBitsAvailable = 0; // :uint;\n // ():uint\n\n this.length = function () {\n return 8 * workingBytesAvailable;\n }; // ():uint\n\n\n this.bitsAvailable = function () {\n return 8 * workingBytesAvailable + workingBitsAvailable;\n }; // ():void\n\n\n this.loadWord = function () {\n var position = workingData.byteLength - workingBytesAvailable,\n workingBytes = new Uint8Array(4),\n availableBytes = Math.min(4, workingBytesAvailable);\n\n if (availableBytes === 0) {\n throw new Error('no bytes available');\n }\n\n workingBytes.set(workingData.subarray(position, position + availableBytes));\n workingWord = new DataView(workingBytes.buffer).getUint32(0); // track the amount of workingData that has been processed\n\n workingBitsAvailable = availableBytes * 8;\n workingBytesAvailable -= availableBytes;\n }; // (count:int):void\n\n\n this.skipBits = function (count) {\n var skipBytes; // :int\n\n if (workingBitsAvailable > count) {\n workingWord <<= count;\n workingBitsAvailable -= count;\n } else {\n count -= workingBitsAvailable;\n skipBytes = Math.floor(count / 8);\n count -= skipBytes * 8;\n workingBytesAvailable -= skipBytes;\n this.loadWord();\n workingWord <<= count;\n workingBitsAvailable -= count;\n }\n }; // (size:int):uint\n\n\n this.readBits = function (size) {\n var bits = Math.min(workingBitsAvailable, size),\n // :uint\n valu = workingWord >>> 32 - bits; // :uint\n // if size > 31, handle error\n\n workingBitsAvailable -= bits;\n\n if (workingBitsAvailable > 0) {\n workingWord <<= bits;\n } else if (workingBytesAvailable > 0) {\n this.loadWord();\n }\n\n bits = size - bits;\n\n if (bits > 0) {\n return valu << bits | this.readBits(bits);\n }\n\n return valu;\n }; // ():uint\n\n\n this.skipLeadingZeros = function () {\n var leadingZeroCount; // :uint\n\n for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) {\n if ((workingWord & 0x80000000 >>> leadingZeroCount) !== 0) {\n // the first bit of working word is 1\n workingWord <<= leadingZeroCount;\n workingBitsAvailable -= leadingZeroCount;\n return leadingZeroCount;\n }\n } // we exhausted workingWord and still have not found a 1\n\n\n this.loadWord();\n return leadingZeroCount + this.skipLeadingZeros();\n }; // ():void\n\n\n this.skipUnsignedExpGolomb = function () {\n this.skipBits(1 + this.skipLeadingZeros());\n }; // ():void\n\n\n this.skipExpGolomb = function () {\n this.skipBits(1 + this.skipLeadingZeros());\n }; // ():uint\n\n\n this.readUnsignedExpGolomb = function () {\n var clz = this.skipLeadingZeros(); // :uint\n\n return this.readBits(clz + 1) - 1;\n }; // ():int\n\n\n this.readExpGolomb = function () {\n var valu = this.readUnsignedExpGolomb(); // :int\n\n if (0x01 & valu) {\n // the number is odd if the low order bit is set\n return 1 + valu >>> 1; // add 1 to make it even, and divide by 2\n }\n\n return -1 * (valu >>> 1); // divide by two then make it negative\n }; // Some convenience functions\n // :Boolean\n\n\n this.readBoolean = function () {\n return this.readBits(1) === 1;\n }; // ():int\n\n\n this.readUnsignedByte = function () {\n return this.readBits(8);\n };\n\n this.loadWord();\n };\n\n var expGolomb = ExpGolomb$1;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var Stream$2 = stream;\n var ExpGolomb = expGolomb;\n var H264Stream$1, NalByteStream;\n var PROFILES_WITH_OPTIONAL_SPS_DATA;\n /**\n * Accepts a NAL unit byte stream and unpacks the embedded NAL units.\n */\n\n NalByteStream = function () {\n var syncPoint = 0,\n i,\n buffer;\n NalByteStream.prototype.init.call(this);\n /*\n * Scans a byte stream and triggers a data event with the NAL units found.\n * @param {Object} data Event received from H264Stream\n * @param {Uint8Array} data.data The h264 byte stream to be scanned\n *\n * @see H264Stream.push\n */\n\n this.push = function (data) {\n var swapBuffer;\n\n if (!buffer) {\n buffer = data.data;\n } else {\n swapBuffer = new Uint8Array(buffer.byteLength + data.data.byteLength);\n swapBuffer.set(buffer);\n swapBuffer.set(data.data, buffer.byteLength);\n buffer = swapBuffer;\n }\n\n var len = buffer.byteLength; // Rec. ITU-T H.264, Annex B\n // scan for NAL unit boundaries\n // a match looks like this:\n // 0 0 1 .. NAL .. 0 0 1\n // ^ sync point ^ i\n // or this:\n // 0 0 1 .. NAL .. 0 0 0\n // ^ sync point ^ i\n // advance the sync point to a NAL start, if necessary\n\n for (; syncPoint < len - 3; syncPoint++) {\n if (buffer[syncPoint + 2] === 1) {\n // the sync point is properly aligned\n i = syncPoint + 5;\n break;\n }\n }\n\n while (i < len) {\n // look at the current byte to determine if we've hit the end of\n // a NAL unit boundary\n switch (buffer[i]) {\n case 0:\n // skip past non-sync sequences\n if (buffer[i - 1] !== 0) {\n i += 2;\n break;\n } else if (buffer[i - 2] !== 0) {\n i++;\n break;\n } // deliver the NAL unit if it isn't empty\n\n\n if (syncPoint + 3 !== i - 2) {\n this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));\n } // drop trailing zeroes\n\n\n do {\n i++;\n } while (buffer[i] !== 1 && i < len);\n\n syncPoint = i - 2;\n i += 3;\n break;\n\n case 1:\n // skip past non-sync sequences\n if (buffer[i - 1] !== 0 || buffer[i - 2] !== 0) {\n i += 3;\n break;\n } // deliver the NAL unit\n\n\n this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));\n syncPoint = i - 2;\n i += 3;\n break;\n\n default:\n // the current byte isn't a one or zero, so it cannot be part\n // of a sync sequence\n i += 3;\n break;\n }\n } // filter out the NAL units that were delivered\n\n\n buffer = buffer.subarray(syncPoint);\n i -= syncPoint;\n syncPoint = 0;\n };\n\n this.reset = function () {\n buffer = null;\n syncPoint = 0;\n this.trigger('reset');\n };\n\n this.flush = function () {\n // deliver the last buffered NAL unit\n if (buffer && buffer.byteLength > 3) {\n this.trigger('data', buffer.subarray(syncPoint + 3));\n } // reset the stream state\n\n\n buffer = null;\n syncPoint = 0;\n this.trigger('done');\n };\n\n this.endTimeline = function () {\n this.flush();\n this.trigger('endedtimeline');\n };\n };\n\n NalByteStream.prototype = new Stream$2(); // values of profile_idc that indicate additional fields are included in the SPS\n // see Recommendation ITU-T H.264 (4/2013),\n // 7.3.2.1.1 Sequence parameter set data syntax\n\n PROFILES_WITH_OPTIONAL_SPS_DATA = {\n 100: true,\n 110: true,\n 122: true,\n 244: true,\n 44: true,\n 83: true,\n 86: true,\n 118: true,\n 128: true,\n // TODO: the three profiles below don't\n // appear to have sps data in the specificiation anymore?\n 138: true,\n 139: true,\n 134: true\n };\n /**\n * Accepts input from a ElementaryStream and produces H.264 NAL unit data\n * events.\n */\n\n H264Stream$1 = function () {\n var nalByteStream = new NalByteStream(),\n self,\n trackId,\n currentPts,\n currentDts,\n discardEmulationPreventionBytes,\n readSequenceParameterSet,\n skipScalingList;\n H264Stream$1.prototype.init.call(this);\n self = this;\n /*\n * Pushes a packet from a stream onto the NalByteStream\n *\n * @param {Object} packet - A packet received from a stream\n * @param {Uint8Array} packet.data - The raw bytes of the packet\n * @param {Number} packet.dts - Decode timestamp of the packet\n * @param {Number} packet.pts - Presentation timestamp of the packet\n * @param {Number} packet.trackId - The id of the h264 track this packet came from\n * @param {('video'|'audio')} packet.type - The type of packet\n *\n */\n\n this.push = function (packet) {\n if (packet.type !== 'video') {\n return;\n }\n\n trackId = packet.trackId;\n currentPts = packet.pts;\n currentDts = packet.dts;\n nalByteStream.push(packet);\n };\n /*\n * Identify NAL unit types and pass on the NALU, trackId, presentation and decode timestamps\n * for the NALUs to the next stream component.\n * Also, preprocess caption and sequence parameter NALUs.\n *\n * @param {Uint8Array} data - A NAL unit identified by `NalByteStream.push`\n * @see NalByteStream.push\n */\n\n\n nalByteStream.on('data', function (data) {\n var event = {\n trackId: trackId,\n pts: currentPts,\n dts: currentDts,\n data: data,\n nalUnitTypeCode: data[0] & 0x1f\n };\n\n switch (event.nalUnitTypeCode) {\n case 0x05:\n event.nalUnitType = 'slice_layer_without_partitioning_rbsp_idr';\n break;\n\n case 0x06:\n event.nalUnitType = 'sei_rbsp';\n event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));\n break;\n\n case 0x07:\n event.nalUnitType = 'seq_parameter_set_rbsp';\n event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));\n event.config = readSequenceParameterSet(event.escapedRBSP);\n break;\n\n case 0x08:\n event.nalUnitType = 'pic_parameter_set_rbsp';\n break;\n\n case 0x09:\n event.nalUnitType = 'access_unit_delimiter_rbsp';\n break;\n } // This triggers data on the H264Stream\n\n\n self.trigger('data', event);\n });\n nalByteStream.on('done', function () {\n self.trigger('done');\n });\n nalByteStream.on('partialdone', function () {\n self.trigger('partialdone');\n });\n nalByteStream.on('reset', function () {\n self.trigger('reset');\n });\n nalByteStream.on('endedtimeline', function () {\n self.trigger('endedtimeline');\n });\n\n this.flush = function () {\n nalByteStream.flush();\n };\n\n this.partialFlush = function () {\n nalByteStream.partialFlush();\n };\n\n this.reset = function () {\n nalByteStream.reset();\n };\n\n this.endTimeline = function () {\n nalByteStream.endTimeline();\n };\n /**\n * Advance the ExpGolomb decoder past a scaling list. The scaling\n * list is optionally transmitted as part of a sequence parameter\n * set and is not relevant to transmuxing.\n * @param count {number} the number of entries in this scaling list\n * @param expGolombDecoder {object} an ExpGolomb pointed to the\n * start of a scaling list\n * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1\n */\n\n\n skipScalingList = function (count, expGolombDecoder) {\n var lastScale = 8,\n nextScale = 8,\n j,\n deltaScale;\n\n for (j = 0; j < count; j++) {\n if (nextScale !== 0) {\n deltaScale = expGolombDecoder.readExpGolomb();\n nextScale = (lastScale + deltaScale + 256) % 256;\n }\n\n lastScale = nextScale === 0 ? lastScale : nextScale;\n }\n };\n /**\n * Expunge any \"Emulation Prevention\" bytes from a \"Raw Byte\n * Sequence Payload\"\n * @param data {Uint8Array} the bytes of a RBSP from a NAL\n * unit\n * @return {Uint8Array} the RBSP without any Emulation\n * Prevention Bytes\n */\n\n\n discardEmulationPreventionBytes = function (data) {\n var length = data.byteLength,\n emulationPreventionBytesPositions = [],\n i = 1,\n newLength,\n newData; // Find all `Emulation Prevention Bytes`\n\n while (i < length - 2) {\n if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {\n emulationPreventionBytesPositions.push(i + 2);\n i += 2;\n } else {\n i++;\n }\n } // If no Emulation Prevention Bytes were found just return the original\n // array\n\n\n if (emulationPreventionBytesPositions.length === 0) {\n return data;\n } // Create a new array to hold the NAL unit data\n\n\n newLength = length - emulationPreventionBytesPositions.length;\n newData = new Uint8Array(newLength);\n var sourceIndex = 0;\n\n for (i = 0; i < newLength; sourceIndex++, i++) {\n if (sourceIndex === emulationPreventionBytesPositions[0]) {\n // Skip this byte\n sourceIndex++; // Remove this position index\n\n emulationPreventionBytesPositions.shift();\n }\n\n newData[i] = data[sourceIndex];\n }\n\n return newData;\n };\n /**\n * Read a sequence parameter set and return some interesting video\n * properties. A sequence parameter set is the H264 metadata that\n * describes the properties of upcoming video frames.\n * @param data {Uint8Array} the bytes of a sequence parameter set\n * @return {object} an object with configuration parsed from the\n * sequence parameter set, including the dimensions of the\n * associated video frames.\n */\n\n\n readSequenceParameterSet = function (data) {\n var frameCropLeftOffset = 0,\n frameCropRightOffset = 0,\n frameCropTopOffset = 0,\n frameCropBottomOffset = 0,\n expGolombDecoder,\n profileIdc,\n levelIdc,\n profileCompatibility,\n chromaFormatIdc,\n picOrderCntType,\n numRefFramesInPicOrderCntCycle,\n picWidthInMbsMinus1,\n picHeightInMapUnitsMinus1,\n frameMbsOnlyFlag,\n scalingListCount,\n sarRatio = [1, 1],\n aspectRatioIdc,\n i;\n expGolombDecoder = new ExpGolomb(data);\n profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc\n\n profileCompatibility = expGolombDecoder.readUnsignedByte(); // constraint_set[0-5]_flag\n\n levelIdc = expGolombDecoder.readUnsignedByte(); // level_idc u(8)\n\n expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id\n // some profiles have more optional data we don't need\n\n if (PROFILES_WITH_OPTIONAL_SPS_DATA[profileIdc]) {\n chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();\n\n if (chromaFormatIdc === 3) {\n expGolombDecoder.skipBits(1); // separate_colour_plane_flag\n }\n\n expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_luma_minus8\n\n expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8\n\n expGolombDecoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag\n\n if (expGolombDecoder.readBoolean()) {\n // seq_scaling_matrix_present_flag\n scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;\n\n for (i = 0; i < scalingListCount; i++) {\n if (expGolombDecoder.readBoolean()) {\n // seq_scaling_list_present_flag[ i ]\n if (i < 6) {\n skipScalingList(16, expGolombDecoder);\n } else {\n skipScalingList(64, expGolombDecoder);\n }\n }\n }\n }\n }\n\n expGolombDecoder.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4\n\n picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();\n\n if (picOrderCntType === 0) {\n expGolombDecoder.readUnsignedExpGolomb(); // log2_max_pic_order_cnt_lsb_minus4\n } else if (picOrderCntType === 1) {\n expGolombDecoder.skipBits(1); // delta_pic_order_always_zero_flag\n\n expGolombDecoder.skipExpGolomb(); // offset_for_non_ref_pic\n\n expGolombDecoder.skipExpGolomb(); // offset_for_top_to_bottom_field\n\n numRefFramesInPicOrderCntCycle = expGolombDecoder.readUnsignedExpGolomb();\n\n for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {\n expGolombDecoder.skipExpGolomb(); // offset_for_ref_frame[ i ]\n }\n }\n\n expGolombDecoder.skipUnsignedExpGolomb(); // max_num_ref_frames\n\n expGolombDecoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag\n\n picWidthInMbsMinus1 = expGolombDecoder.readUnsignedExpGolomb();\n picHeightInMapUnitsMinus1 = expGolombDecoder.readUnsignedExpGolomb();\n frameMbsOnlyFlag = expGolombDecoder.readBits(1);\n\n if (frameMbsOnlyFlag === 0) {\n expGolombDecoder.skipBits(1); // mb_adaptive_frame_field_flag\n }\n\n expGolombDecoder.skipBits(1); // direct_8x8_inference_flag\n\n if (expGolombDecoder.readBoolean()) {\n // frame_cropping_flag\n frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();\n frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();\n frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();\n frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();\n }\n\n if (expGolombDecoder.readBoolean()) {\n // vui_parameters_present_flag\n if (expGolombDecoder.readBoolean()) {\n // aspect_ratio_info_present_flag\n aspectRatioIdc = expGolombDecoder.readUnsignedByte();\n\n switch (aspectRatioIdc) {\n case 1:\n sarRatio = [1, 1];\n break;\n\n case 2:\n sarRatio = [12, 11];\n break;\n\n case 3:\n sarRatio = [10, 11];\n break;\n\n case 4:\n sarRatio = [16, 11];\n break;\n\n case 5:\n sarRatio = [40, 33];\n break;\n\n case 6:\n sarRatio = [24, 11];\n break;\n\n case 7:\n sarRatio = [20, 11];\n break;\n\n case 8:\n sarRatio = [32, 11];\n break;\n\n case 9:\n sarRatio = [80, 33];\n break;\n\n case 10:\n sarRatio = [18, 11];\n break;\n\n case 11:\n sarRatio = [15, 11];\n break;\n\n case 12:\n sarRatio = [64, 33];\n break;\n\n case 13:\n sarRatio = [160, 99];\n break;\n\n case 14:\n sarRatio = [4, 3];\n break;\n\n case 15:\n sarRatio = [3, 2];\n break;\n\n case 16:\n sarRatio = [2, 1];\n break;\n\n case 255:\n {\n sarRatio = [expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte(), expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte()];\n break;\n }\n }\n\n if (sarRatio) {\n sarRatio[0] / sarRatio[1];\n }\n }\n }\n\n return {\n profileIdc: profileIdc,\n levelIdc: levelIdc,\n profileCompatibility: profileCompatibility,\n width: (picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2,\n height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - frameCropTopOffset * 2 - frameCropBottomOffset * 2,\n // sar is sample aspect ratio\n sarRatio: sarRatio\n };\n };\n };\n\n H264Stream$1.prototype = new Stream$2();\n var h264 = {\n H264Stream: H264Stream$1,\n NalByteStream: NalByteStream\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Utilities to detect basic properties and metadata about Aac data.\n */\n\n var ADTS_SAMPLING_FREQUENCIES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];\n\n var parseId3TagSize = function (header, byteIndex) {\n var returnSize = header[byteIndex + 6] << 21 | header[byteIndex + 7] << 14 | header[byteIndex + 8] << 7 | header[byteIndex + 9],\n flags = header[byteIndex + 5],\n footerPresent = (flags & 16) >> 4; // if we get a negative returnSize clamp it to 0\n\n returnSize = returnSize >= 0 ? returnSize : 0;\n\n if (footerPresent) {\n return returnSize + 20;\n }\n\n return returnSize + 10;\n };\n\n var getId3Offset = function (data, offset) {\n if (data.length - offset < 10 || data[offset] !== 'I'.charCodeAt(0) || data[offset + 1] !== 'D'.charCodeAt(0) || data[offset + 2] !== '3'.charCodeAt(0)) {\n return offset;\n }\n\n offset += parseId3TagSize(data, offset);\n return getId3Offset(data, offset);\n }; // TODO: use vhs-utils\n\n\n var isLikelyAacData$1 = function (data) {\n var offset = getId3Offset(data, 0);\n return data.length >= offset + 2 && (data[offset] & 0xFF) === 0xFF && (data[offset + 1] & 0xF0) === 0xF0 && // verify that the 2 layer bits are 0, aka this\n // is not mp3 data but aac data.\n (data[offset + 1] & 0x16) === 0x10;\n };\n\n var parseSyncSafeInteger = function (data) {\n return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];\n }; // return a percent-encoded representation of the specified byte range\n // @see http://en.wikipedia.org/wiki/Percent-encoding\n\n\n var percentEncode = function (bytes, start, end) {\n var i,\n result = '';\n\n for (i = start; i < end; i++) {\n result += '%' + ('00' + bytes[i].toString(16)).slice(-2);\n }\n\n return result;\n }; // return the string representation of the specified byte range,\n // interpreted as ISO-8859-1.\n\n\n var parseIso88591 = function (bytes, start, end) {\n return unescape(percentEncode(bytes, start, end)); // jshint ignore:line\n };\n\n var parseAdtsSize = function (header, byteIndex) {\n var lowThree = (header[byteIndex + 5] & 0xE0) >> 5,\n middle = header[byteIndex + 4] << 3,\n highTwo = header[byteIndex + 3] & 0x3 << 11;\n return highTwo | middle | lowThree;\n };\n\n var parseType$5 = function (header, byteIndex) {\n if (header[byteIndex] === 'I'.charCodeAt(0) && header[byteIndex + 1] === 'D'.charCodeAt(0) && header[byteIndex + 2] === '3'.charCodeAt(0)) {\n return 'timed-metadata';\n } else if (header[byteIndex] & 0xff === 0xff && (header[byteIndex + 1] & 0xf0) === 0xf0) {\n return 'audio';\n }\n\n return null;\n };\n\n var parseSampleRate = function (packet) {\n var i = 0;\n\n while (i + 5 < packet.length) {\n if (packet[i] !== 0xFF || (packet[i + 1] & 0xF6) !== 0xF0) {\n // If a valid header was not found, jump one forward and attempt to\n // find a valid ADTS header starting at the next byte\n i++;\n continue;\n }\n\n return ADTS_SAMPLING_FREQUENCIES[(packet[i + 2] & 0x3c) >>> 2];\n }\n\n return null;\n };\n\n var parseAacTimestamp = function (packet) {\n var frameStart, frameSize, frame, frameHeader; // find the start of the first frame and the end of the tag\n\n frameStart = 10;\n\n if (packet[5] & 0x40) {\n // advance the frame start past the extended header\n frameStart += 4; // header size field\n\n frameStart += parseSyncSafeInteger(packet.subarray(10, 14));\n } // parse one or more ID3 frames\n // http://id3.org/id3v2.3.0#ID3v2_frame_overview\n\n\n do {\n // determine the number of bytes in this frame\n frameSize = parseSyncSafeInteger(packet.subarray(frameStart + 4, frameStart + 8));\n\n if (frameSize < 1) {\n return null;\n }\n\n frameHeader = String.fromCharCode(packet[frameStart], packet[frameStart + 1], packet[frameStart + 2], packet[frameStart + 3]);\n\n if (frameHeader === 'PRIV') {\n frame = packet.subarray(frameStart + 10, frameStart + frameSize + 10);\n\n for (var i = 0; i < frame.byteLength; i++) {\n if (frame[i] === 0) {\n var owner = parseIso88591(frame, 0, i);\n\n if (owner === 'com.apple.streaming.transportStreamTimestamp') {\n var d = frame.subarray(i + 1);\n var size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;\n size *= 4;\n size += d[7] & 0x03;\n return size;\n }\n\n break;\n }\n }\n }\n\n frameStart += 10; // advance past the frame header\n\n frameStart += frameSize; // advance past the frame body\n } while (frameStart < packet.byteLength);\n\n return null;\n };\n\n var utils = {\n isLikelyAacData: isLikelyAacData$1,\n parseId3TagSize: parseId3TagSize,\n parseAdtsSize: parseAdtsSize,\n parseType: parseType$5,\n parseSampleRate: parseSampleRate,\n parseAacTimestamp: parseAacTimestamp\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * A stream-based aac to mp4 converter. This utility can be used to\n * deliver mp4s to a SourceBuffer on platforms that support native\n * Media Source Extensions.\n */\n\n var Stream$1 = stream;\n var aacUtils = utils; // Constants\n\n var AacStream$1;\n /**\n * Splits an incoming stream of binary data into ADTS and ID3 Frames.\n */\n\n AacStream$1 = function () {\n var everything = new Uint8Array(),\n timeStamp = 0;\n AacStream$1.prototype.init.call(this);\n\n this.setTimestamp = function (timestamp) {\n timeStamp = timestamp;\n };\n\n this.push = function (bytes) {\n var frameSize = 0,\n byteIndex = 0,\n bytesLeft,\n chunk,\n packet,\n tempLength; // If there are bytes remaining from the last segment, prepend them to the\n // bytes that were pushed in\n\n if (everything.length) {\n tempLength = everything.length;\n everything = new Uint8Array(bytes.byteLength + tempLength);\n everything.set(everything.subarray(0, tempLength));\n everything.set(bytes, tempLength);\n } else {\n everything = bytes;\n }\n\n while (everything.length - byteIndex >= 3) {\n if (everything[byteIndex] === 'I'.charCodeAt(0) && everything[byteIndex + 1] === 'D'.charCodeAt(0) && everything[byteIndex + 2] === '3'.charCodeAt(0)) {\n // Exit early because we don't have enough to parse\n // the ID3 tag header\n if (everything.length - byteIndex < 10) {\n break;\n } // check framesize\n\n\n frameSize = aacUtils.parseId3TagSize(everything, byteIndex); // Exit early if we don't have enough in the buffer\n // to emit a full packet\n // Add to byteIndex to support multiple ID3 tags in sequence\n\n if (byteIndex + frameSize > everything.length) {\n break;\n }\n\n chunk = {\n type: 'timed-metadata',\n data: everything.subarray(byteIndex, byteIndex + frameSize)\n };\n this.trigger('data', chunk);\n byteIndex += frameSize;\n continue;\n } else if ((everything[byteIndex] & 0xff) === 0xff && (everything[byteIndex + 1] & 0xf0) === 0xf0) {\n // Exit early because we don't have enough to parse\n // the ADTS frame header\n if (everything.length - byteIndex < 7) {\n break;\n }\n\n frameSize = aacUtils.parseAdtsSize(everything, byteIndex); // Exit early if we don't have enough in the buffer\n // to emit a full packet\n\n if (byteIndex + frameSize > everything.length) {\n break;\n }\n\n packet = {\n type: 'audio',\n data: everything.subarray(byteIndex, byteIndex + frameSize),\n pts: timeStamp,\n dts: timeStamp\n };\n this.trigger('data', packet);\n byteIndex += frameSize;\n continue;\n }\n\n byteIndex++;\n }\n\n bytesLeft = everything.length - byteIndex;\n\n if (bytesLeft > 0) {\n everything = everything.subarray(byteIndex);\n } else {\n everything = new Uint8Array();\n }\n };\n\n this.reset = function () {\n everything = new Uint8Array();\n this.trigger('reset');\n };\n\n this.endTimeline = function () {\n everything = new Uint8Array();\n this.trigger('endedtimeline');\n };\n };\n\n AacStream$1.prototype = new Stream$1();\n var aac = AacStream$1;\n var AUDIO_PROPERTIES$1 = ['audioobjecttype', 'channelcount', 'samplerate', 'samplingfrequencyindex', 'samplesize'];\n var audioProperties = AUDIO_PROPERTIES$1;\n var VIDEO_PROPERTIES$1 = ['width', 'height', 'profileIdc', 'levelIdc', 'profileCompatibility', 'sarRatio'];\n var videoProperties = VIDEO_PROPERTIES$1;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * A stream-based mp2t to mp4 converter. This utility can be used to\n * deliver mp4s to a SourceBuffer on platforms that support native\n * Media Source Extensions.\n */\n\n var Stream = stream;\n var mp4 = mp4Generator;\n var frameUtils = frameUtils$1;\n var audioFrameUtils = audioFrameUtils$1;\n var trackDecodeInfo = trackDecodeInfo$1;\n var m2ts = m2ts_1;\n var clock = clock$2;\n var AdtsStream = adts;\n var H264Stream = h264.H264Stream;\n var AacStream = aac;\n var isLikelyAacData = utils.isLikelyAacData;\n var ONE_SECOND_IN_TS$1 = clock$2.ONE_SECOND_IN_TS;\n var AUDIO_PROPERTIES = audioProperties;\n var VIDEO_PROPERTIES = videoProperties; // object types\n\n var VideoSegmentStream, AudioSegmentStream, Transmuxer, CoalesceStream;\n\n var retriggerForStream = function (key, event) {\n event.stream = key;\n this.trigger('log', event);\n };\n\n var addPipelineLogRetriggers = function (transmuxer, pipeline) {\n var keys = Object.keys(pipeline);\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i]; // skip non-stream keys and headOfPipeline\n // which is just a duplicate\n\n if (key === 'headOfPipeline' || !pipeline[key].on) {\n continue;\n }\n\n pipeline[key].on('log', retriggerForStream.bind(transmuxer, key));\n }\n };\n /**\n * Compare two arrays (even typed) for same-ness\n */\n\n\n var arrayEquals = function (a, b) {\n var i;\n\n if (a.length !== b.length) {\n return false;\n } // compare the value of each element in the array\n\n\n for (i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n\n return true;\n };\n\n var generateSegmentTimingInfo = function (baseMediaDecodeTime, startDts, startPts, endDts, endPts, prependedContentDuration) {\n var ptsOffsetFromDts = startPts - startDts,\n decodeDuration = endDts - startDts,\n presentationDuration = endPts - startPts; // The PTS and DTS values are based on the actual stream times from the segment,\n // however, the player time values will reflect a start from the baseMediaDecodeTime.\n // In order to provide relevant values for the player times, base timing info on the\n // baseMediaDecodeTime and the DTS and PTS durations of the segment.\n\n return {\n start: {\n dts: baseMediaDecodeTime,\n pts: baseMediaDecodeTime + ptsOffsetFromDts\n },\n end: {\n dts: baseMediaDecodeTime + decodeDuration,\n pts: baseMediaDecodeTime + presentationDuration\n },\n prependedContentDuration: prependedContentDuration,\n baseMediaDecodeTime: baseMediaDecodeTime\n };\n };\n /**\n * Constructs a single-track, ISO BMFF media segment from AAC data\n * events. The output of this stream can be fed to a SourceBuffer\n * configured with a suitable initialization segment.\n * @param track {object} track metadata configuration\n * @param options {object} transmuxer options object\n * @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps\n * in the source; false to adjust the first segment to start at 0.\n */\n\n\n AudioSegmentStream = function (track, options) {\n var adtsFrames = [],\n sequenceNumber,\n earliestAllowedDts = 0,\n audioAppendStartTs = 0,\n videoBaseMediaDecodeTime = Infinity;\n options = options || {};\n sequenceNumber = options.firstSequenceNumber || 0;\n AudioSegmentStream.prototype.init.call(this);\n\n this.push = function (data) {\n trackDecodeInfo.collectDtsInfo(track, data);\n\n if (track) {\n AUDIO_PROPERTIES.forEach(function (prop) {\n track[prop] = data[prop];\n });\n } // buffer audio data until end() is called\n\n\n adtsFrames.push(data);\n };\n\n this.setEarliestDts = function (earliestDts) {\n earliestAllowedDts = earliestDts;\n };\n\n this.setVideoBaseMediaDecodeTime = function (baseMediaDecodeTime) {\n videoBaseMediaDecodeTime = baseMediaDecodeTime;\n };\n\n this.setAudioAppendStart = function (timestamp) {\n audioAppendStartTs = timestamp;\n };\n\n this.flush = function () {\n var frames, moof, mdat, boxes, frameDuration, segmentDuration, videoClockCyclesOfSilencePrefixed; // return early if no audio data has been observed\n\n if (adtsFrames.length === 0) {\n this.trigger('done', 'AudioSegmentStream');\n return;\n }\n\n frames = audioFrameUtils.trimAdtsFramesByEarliestDts(adtsFrames, track, earliestAllowedDts);\n track.baseMediaDecodeTime = trackDecodeInfo.calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps); // amount of audio filled but the value is in video clock rather than audio clock\n\n videoClockCyclesOfSilencePrefixed = audioFrameUtils.prefixWithSilence(track, frames, audioAppendStartTs, videoBaseMediaDecodeTime); // we have to build the index from byte locations to\n // samples (that is, adts frames) in the audio data\n\n track.samples = audioFrameUtils.generateSampleTable(frames); // concatenate the audio data to constuct the mdat\n\n mdat = mp4.mdat(audioFrameUtils.concatenateFrameData(frames));\n adtsFrames = [];\n moof = mp4.moof(sequenceNumber, [track]);\n boxes = new Uint8Array(moof.byteLength + mdat.byteLength); // bump the sequence number for next time\n\n sequenceNumber++;\n boxes.set(moof);\n boxes.set(mdat, moof.byteLength);\n trackDecodeInfo.clearDtsInfo(track);\n frameDuration = Math.ceil(ONE_SECOND_IN_TS$1 * 1024 / track.samplerate); // TODO this check was added to maintain backwards compatibility (particularly with\n // tests) on adding the timingInfo event. However, it seems unlikely that there's a\n // valid use-case where an init segment/data should be triggered without associated\n // frames. Leaving for now, but should be looked into.\n\n if (frames.length) {\n segmentDuration = frames.length * frameDuration;\n this.trigger('segmentTimingInfo', generateSegmentTimingInfo( // The audio track's baseMediaDecodeTime is in audio clock cycles, but the\n // frame info is in video clock cycles. Convert to match expectation of\n // listeners (that all timestamps will be based on video clock cycles).\n clock.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate), // frame times are already in video clock, as is segment duration\n frames[0].dts, frames[0].pts, frames[0].dts + segmentDuration, frames[0].pts + segmentDuration, videoClockCyclesOfSilencePrefixed || 0));\n this.trigger('timingInfo', {\n start: frames[0].pts,\n end: frames[0].pts + segmentDuration\n });\n }\n\n this.trigger('data', {\n track: track,\n boxes: boxes\n });\n this.trigger('done', 'AudioSegmentStream');\n };\n\n this.reset = function () {\n trackDecodeInfo.clearDtsInfo(track);\n adtsFrames = [];\n this.trigger('reset');\n };\n };\n\n AudioSegmentStream.prototype = new Stream();\n /**\n * Constructs a single-track, ISO BMFF media segment from H264 data\n * events. The output of this stream can be fed to a SourceBuffer\n * configured with a suitable initialization segment.\n * @param track {object} track metadata configuration\n * @param options {object} transmuxer options object\n * @param options.alignGopsAtEnd {boolean} If true, start from the end of the\n * gopsToAlignWith list when attempting to align gop pts\n * @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps\n * in the source; false to adjust the first segment to start at 0.\n */\n\n VideoSegmentStream = function (track, options) {\n var sequenceNumber,\n nalUnits = [],\n gopsToAlignWith = [],\n config,\n pps;\n options = options || {};\n sequenceNumber = options.firstSequenceNumber || 0;\n VideoSegmentStream.prototype.init.call(this);\n delete track.minPTS;\n this.gopCache_ = [];\n /**\n * Constructs a ISO BMFF segment given H264 nalUnits\n * @param {Object} nalUnit A data event representing a nalUnit\n * @param {String} nalUnit.nalUnitType\n * @param {Object} nalUnit.config Properties for a mp4 track\n * @param {Uint8Array} nalUnit.data The nalUnit bytes\n * @see lib/codecs/h264.js\n **/\n\n this.push = function (nalUnit) {\n trackDecodeInfo.collectDtsInfo(track, nalUnit); // record the track config\n\n if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp' && !config) {\n config = nalUnit.config;\n track.sps = [nalUnit.data];\n VIDEO_PROPERTIES.forEach(function (prop) {\n track[prop] = config[prop];\n }, this);\n }\n\n if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp' && !pps) {\n pps = nalUnit.data;\n track.pps = [nalUnit.data];\n } // buffer video until flush() is called\n\n\n nalUnits.push(nalUnit);\n };\n /**\n * Pass constructed ISO BMFF track and boxes on to the\n * next stream in the pipeline\n **/\n\n\n this.flush = function () {\n var frames,\n gopForFusion,\n gops,\n moof,\n mdat,\n boxes,\n prependedContentDuration = 0,\n firstGop,\n lastGop; // Throw away nalUnits at the start of the byte stream until\n // we find the first AUD\n\n while (nalUnits.length) {\n if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') {\n break;\n }\n\n nalUnits.shift();\n } // Return early if no video data has been observed\n\n\n if (nalUnits.length === 0) {\n this.resetStream_();\n this.trigger('done', 'VideoSegmentStream');\n return;\n } // Organize the raw nal-units into arrays that represent\n // higher-level constructs such as frames and gops\n // (group-of-pictures)\n\n\n frames = frameUtils.groupNalsIntoFrames(nalUnits);\n gops = frameUtils.groupFramesIntoGops(frames); // If the first frame of this fragment is not a keyframe we have\n // a problem since MSE (on Chrome) requires a leading keyframe.\n //\n // We have two approaches to repairing this situation:\n // 1) GOP-FUSION:\n // This is where we keep track of the GOPS (group-of-pictures)\n // from previous fragments and attempt to find one that we can\n // prepend to the current fragment in order to create a valid\n // fragment.\n // 2) KEYFRAME-PULLING:\n // Here we search for the first keyframe in the fragment and\n // throw away all the frames between the start of the fragment\n // and that keyframe. We then extend the duration and pull the\n // PTS of the keyframe forward so that it covers the time range\n // of the frames that were disposed of.\n //\n // #1 is far prefereable over #2 which can cause \"stuttering\" but\n // requires more things to be just right.\n\n if (!gops[0][0].keyFrame) {\n // Search for a gop for fusion from our gopCache\n gopForFusion = this.getGopForFusion_(nalUnits[0], track);\n\n if (gopForFusion) {\n // in order to provide more accurate timing information about the segment, save\n // the number of seconds prepended to the original segment due to GOP fusion\n prependedContentDuration = gopForFusion.duration;\n gops.unshift(gopForFusion); // Adjust Gops' metadata to account for the inclusion of the\n // new gop at the beginning\n\n gops.byteLength += gopForFusion.byteLength;\n gops.nalCount += gopForFusion.nalCount;\n gops.pts = gopForFusion.pts;\n gops.dts = gopForFusion.dts;\n gops.duration += gopForFusion.duration;\n } else {\n // If we didn't find a candidate gop fall back to keyframe-pulling\n gops = frameUtils.extendFirstKeyFrame(gops);\n }\n } // Trim gops to align with gopsToAlignWith\n\n\n if (gopsToAlignWith.length) {\n var alignedGops;\n\n if (options.alignGopsAtEnd) {\n alignedGops = this.alignGopsAtEnd_(gops);\n } else {\n alignedGops = this.alignGopsAtStart_(gops);\n }\n\n if (!alignedGops) {\n // save all the nals in the last GOP into the gop cache\n this.gopCache_.unshift({\n gop: gops.pop(),\n pps: track.pps,\n sps: track.sps\n }); // Keep a maximum of 6 GOPs in the cache\n\n this.gopCache_.length = Math.min(6, this.gopCache_.length); // Clear nalUnits\n\n nalUnits = []; // return early no gops can be aligned with desired gopsToAlignWith\n\n this.resetStream_();\n this.trigger('done', 'VideoSegmentStream');\n return;\n } // Some gops were trimmed. clear dts info so minSegmentDts and pts are correct\n // when recalculated before sending off to CoalesceStream\n\n\n trackDecodeInfo.clearDtsInfo(track);\n gops = alignedGops;\n }\n\n trackDecodeInfo.collectDtsInfo(track, gops); // First, we have to build the index from byte locations to\n // samples (that is, frames) in the video data\n\n track.samples = frameUtils.generateSampleTable(gops); // Concatenate the video data and construct the mdat\n\n mdat = mp4.mdat(frameUtils.concatenateNalData(gops));\n track.baseMediaDecodeTime = trackDecodeInfo.calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps);\n this.trigger('processedGopsInfo', gops.map(function (gop) {\n return {\n pts: gop.pts,\n dts: gop.dts,\n byteLength: gop.byteLength\n };\n }));\n firstGop = gops[0];\n lastGop = gops[gops.length - 1];\n this.trigger('segmentTimingInfo', generateSegmentTimingInfo(track.baseMediaDecodeTime, firstGop.dts, firstGop.pts, lastGop.dts + lastGop.duration, lastGop.pts + lastGop.duration, prependedContentDuration));\n this.trigger('timingInfo', {\n start: gops[0].pts,\n end: gops[gops.length - 1].pts + gops[gops.length - 1].duration\n }); // save all the nals in the last GOP into the gop cache\n\n this.gopCache_.unshift({\n gop: gops.pop(),\n pps: track.pps,\n sps: track.sps\n }); // Keep a maximum of 6 GOPs in the cache\n\n this.gopCache_.length = Math.min(6, this.gopCache_.length); // Clear nalUnits\n\n nalUnits = [];\n this.trigger('baseMediaDecodeTime', track.baseMediaDecodeTime);\n this.trigger('timelineStartInfo', track.timelineStartInfo);\n moof = mp4.moof(sequenceNumber, [track]); // it would be great to allocate this array up front instead of\n // throwing away hundreds of media segment fragments\n\n boxes = new Uint8Array(moof.byteLength + mdat.byteLength); // Bump the sequence number for next time\n\n sequenceNumber++;\n boxes.set(moof);\n boxes.set(mdat, moof.byteLength);\n this.trigger('data', {\n track: track,\n boxes: boxes\n });\n this.resetStream_(); // Continue with the flush process now\n\n this.trigger('done', 'VideoSegmentStream');\n };\n\n this.reset = function () {\n this.resetStream_();\n nalUnits = [];\n this.gopCache_.length = 0;\n gopsToAlignWith.length = 0;\n this.trigger('reset');\n };\n\n this.resetStream_ = function () {\n trackDecodeInfo.clearDtsInfo(track); // reset config and pps because they may differ across segments\n // for instance, when we are rendition switching\n\n config = undefined;\n pps = undefined;\n }; // Search for a candidate Gop for gop-fusion from the gop cache and\n // return it or return null if no good candidate was found\n\n\n this.getGopForFusion_ = function (nalUnit) {\n var halfSecond = 45000,\n // Half-a-second in a 90khz clock\n allowableOverlap = 10000,\n // About 3 frames @ 30fps\n nearestDistance = Infinity,\n dtsDistance,\n nearestGopObj,\n currentGop,\n currentGopObj,\n i; // Search for the GOP nearest to the beginning of this nal unit\n\n for (i = 0; i < this.gopCache_.length; i++) {\n currentGopObj = this.gopCache_[i];\n currentGop = currentGopObj.gop; // Reject Gops with different SPS or PPS\n\n if (!(track.pps && arrayEquals(track.pps[0], currentGopObj.pps[0])) || !(track.sps && arrayEquals(track.sps[0], currentGopObj.sps[0]))) {\n continue;\n } // Reject Gops that would require a negative baseMediaDecodeTime\n\n\n if (currentGop.dts < track.timelineStartInfo.dts) {\n continue;\n } // The distance between the end of the gop and the start of the nalUnit\n\n\n dtsDistance = nalUnit.dts - currentGop.dts - currentGop.duration; // Only consider GOPS that start before the nal unit and end within\n // a half-second of the nal unit\n\n if (dtsDistance >= -allowableOverlap && dtsDistance <= halfSecond) {\n // Always use the closest GOP we found if there is more than\n // one candidate\n if (!nearestGopObj || nearestDistance > dtsDistance) {\n nearestGopObj = currentGopObj;\n nearestDistance = dtsDistance;\n }\n }\n }\n\n if (nearestGopObj) {\n return nearestGopObj.gop;\n }\n\n return null;\n }; // trim gop list to the first gop found that has a matching pts with a gop in the list\n // of gopsToAlignWith starting from the START of the list\n\n\n this.alignGopsAtStart_ = function (gops) {\n var alignIndex, gopIndex, align, gop, byteLength, nalCount, duration, alignedGops;\n byteLength = gops.byteLength;\n nalCount = gops.nalCount;\n duration = gops.duration;\n alignIndex = gopIndex = 0;\n\n while (alignIndex < gopsToAlignWith.length && gopIndex < gops.length) {\n align = gopsToAlignWith[alignIndex];\n gop = gops[gopIndex];\n\n if (align.pts === gop.pts) {\n break;\n }\n\n if (gop.pts > align.pts) {\n // this current gop starts after the current gop we want to align on, so increment\n // align index\n alignIndex++;\n continue;\n } // current gop starts before the current gop we want to align on. so increment gop\n // index\n\n\n gopIndex++;\n byteLength -= gop.byteLength;\n nalCount -= gop.nalCount;\n duration -= gop.duration;\n }\n\n if (gopIndex === 0) {\n // no gops to trim\n return gops;\n }\n\n if (gopIndex === gops.length) {\n // all gops trimmed, skip appending all gops\n return null;\n }\n\n alignedGops = gops.slice(gopIndex);\n alignedGops.byteLength = byteLength;\n alignedGops.duration = duration;\n alignedGops.nalCount = nalCount;\n alignedGops.pts = alignedGops[0].pts;\n alignedGops.dts = alignedGops[0].dts;\n return alignedGops;\n }; // trim gop list to the first gop found that has a matching pts with a gop in the list\n // of gopsToAlignWith starting from the END of the list\n\n\n this.alignGopsAtEnd_ = function (gops) {\n var alignIndex, gopIndex, align, gop, alignEndIndex, matchFound;\n alignIndex = gopsToAlignWith.length - 1;\n gopIndex = gops.length - 1;\n alignEndIndex = null;\n matchFound = false;\n\n while (alignIndex >= 0 && gopIndex >= 0) {\n align = gopsToAlignWith[alignIndex];\n gop = gops[gopIndex];\n\n if (align.pts === gop.pts) {\n matchFound = true;\n break;\n }\n\n if (align.pts > gop.pts) {\n alignIndex--;\n continue;\n }\n\n if (alignIndex === gopsToAlignWith.length - 1) {\n // gop.pts is greater than the last alignment candidate. If no match is found\n // by the end of this loop, we still want to append gops that come after this\n // point\n alignEndIndex = gopIndex;\n }\n\n gopIndex--;\n }\n\n if (!matchFound && alignEndIndex === null) {\n return null;\n }\n\n var trimIndex;\n\n if (matchFound) {\n trimIndex = gopIndex;\n } else {\n trimIndex = alignEndIndex;\n }\n\n if (trimIndex === 0) {\n return gops;\n }\n\n var alignedGops = gops.slice(trimIndex);\n var metadata = alignedGops.reduce(function (total, gop) {\n total.byteLength += gop.byteLength;\n total.duration += gop.duration;\n total.nalCount += gop.nalCount;\n return total;\n }, {\n byteLength: 0,\n duration: 0,\n nalCount: 0\n });\n alignedGops.byteLength = metadata.byteLength;\n alignedGops.duration = metadata.duration;\n alignedGops.nalCount = metadata.nalCount;\n alignedGops.pts = alignedGops[0].pts;\n alignedGops.dts = alignedGops[0].dts;\n return alignedGops;\n };\n\n this.alignGopsWith = function (newGopsToAlignWith) {\n gopsToAlignWith = newGopsToAlignWith;\n };\n };\n\n VideoSegmentStream.prototype = new Stream();\n /**\n * A Stream that can combine multiple streams (ie. audio & video)\n * into a single output segment for MSE. Also supports audio-only\n * and video-only streams.\n * @param options {object} transmuxer options object\n * @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps\n * in the source; false to adjust the first segment to start at media timeline start.\n */\n\n CoalesceStream = function (options, metadataStream) {\n // Number of Tracks per output segment\n // If greater than 1, we combine multiple\n // tracks into a single segment\n this.numberOfTracks = 0;\n this.metadataStream = metadataStream;\n options = options || {};\n\n if (typeof options.remux !== 'undefined') {\n this.remuxTracks = !!options.remux;\n } else {\n this.remuxTracks = true;\n }\n\n if (typeof options.keepOriginalTimestamps === 'boolean') {\n this.keepOriginalTimestamps = options.keepOriginalTimestamps;\n } else {\n this.keepOriginalTimestamps = false;\n }\n\n this.pendingTracks = [];\n this.videoTrack = null;\n this.pendingBoxes = [];\n this.pendingCaptions = [];\n this.pendingMetadata = [];\n this.pendingBytes = 0;\n this.emittedTracks = 0;\n CoalesceStream.prototype.init.call(this); // Take output from multiple\n\n this.push = function (output) {\n // buffer incoming captions until the associated video segment\n // finishes\n if (output.content || output.text) {\n return this.pendingCaptions.push(output);\n } // buffer incoming id3 tags until the final flush\n\n\n if (output.frames) {\n return this.pendingMetadata.push(output);\n } // Add this track to the list of pending tracks and store\n // important information required for the construction of\n // the final segment\n\n\n this.pendingTracks.push(output.track);\n this.pendingBytes += output.boxes.byteLength; // TODO: is there an issue for this against chrome?\n // We unshift audio and push video because\n // as of Chrome 75 when switching from\n // one init segment to another if the video\n // mdat does not appear after the audio mdat\n // only audio will play for the duration of our transmux.\n\n if (output.track.type === 'video') {\n this.videoTrack = output.track;\n this.pendingBoxes.push(output.boxes);\n }\n\n if (output.track.type === 'audio') {\n this.audioTrack = output.track;\n this.pendingBoxes.unshift(output.boxes);\n }\n };\n };\n\n CoalesceStream.prototype = new Stream();\n\n CoalesceStream.prototype.flush = function (flushSource) {\n var offset = 0,\n event = {\n captions: [],\n captionStreams: {},\n metadata: [],\n info: {}\n },\n caption,\n id3,\n initSegment,\n timelineStartPts = 0,\n i;\n\n if (this.pendingTracks.length < this.numberOfTracks) {\n if (flushSource !== 'VideoSegmentStream' && flushSource !== 'AudioSegmentStream') {\n // Return because we haven't received a flush from a data-generating\n // portion of the segment (meaning that we have only recieved meta-data\n // or captions.)\n return;\n } else if (this.remuxTracks) {\n // Return until we have enough tracks from the pipeline to remux (if we\n // are remuxing audio and video into a single MP4)\n return;\n } else if (this.pendingTracks.length === 0) {\n // In the case where we receive a flush without any data having been\n // received we consider it an emitted track for the purposes of coalescing\n // `done` events.\n // We do this for the case where there is an audio and video track in the\n // segment but no audio data. (seen in several playlists with alternate\n // audio tracks and no audio present in the main TS segments.)\n this.emittedTracks++;\n\n if (this.emittedTracks >= this.numberOfTracks) {\n this.trigger('done');\n this.emittedTracks = 0;\n }\n\n return;\n }\n }\n\n if (this.videoTrack) {\n timelineStartPts = this.videoTrack.timelineStartInfo.pts;\n VIDEO_PROPERTIES.forEach(function (prop) {\n event.info[prop] = this.videoTrack[prop];\n }, this);\n } else if (this.audioTrack) {\n timelineStartPts = this.audioTrack.timelineStartInfo.pts;\n AUDIO_PROPERTIES.forEach(function (prop) {\n event.info[prop] = this.audioTrack[prop];\n }, this);\n }\n\n if (this.videoTrack || this.audioTrack) {\n if (this.pendingTracks.length === 1) {\n event.type = this.pendingTracks[0].type;\n } else {\n event.type = 'combined';\n }\n\n this.emittedTracks += this.pendingTracks.length;\n initSegment = mp4.initSegment(this.pendingTracks); // Create a new typed array to hold the init segment\n\n event.initSegment = new Uint8Array(initSegment.byteLength); // Create an init segment containing a moov\n // and track definitions\n\n event.initSegment.set(initSegment); // Create a new typed array to hold the moof+mdats\n\n event.data = new Uint8Array(this.pendingBytes); // Append each moof+mdat (one per track) together\n\n for (i = 0; i < this.pendingBoxes.length; i++) {\n event.data.set(this.pendingBoxes[i], offset);\n offset += this.pendingBoxes[i].byteLength;\n } // Translate caption PTS times into second offsets to match the\n // video timeline for the segment, and add track info\n\n\n for (i = 0; i < this.pendingCaptions.length; i++) {\n caption = this.pendingCaptions[i];\n caption.startTime = clock.metadataTsToSeconds(caption.startPts, timelineStartPts, this.keepOriginalTimestamps);\n caption.endTime = clock.metadataTsToSeconds(caption.endPts, timelineStartPts, this.keepOriginalTimestamps);\n event.captionStreams[caption.stream] = true;\n event.captions.push(caption);\n } // Translate ID3 frame PTS times into second offsets to match the\n // video timeline for the segment\n\n\n for (i = 0; i < this.pendingMetadata.length; i++) {\n id3 = this.pendingMetadata[i];\n id3.cueTime = clock.metadataTsToSeconds(id3.pts, timelineStartPts, this.keepOriginalTimestamps);\n event.metadata.push(id3);\n } // We add this to every single emitted segment even though we only need\n // it for the first\n\n\n event.metadata.dispatchType = this.metadataStream.dispatchType; // Reset stream state\n\n this.pendingTracks.length = 0;\n this.videoTrack = null;\n this.pendingBoxes.length = 0;\n this.pendingCaptions.length = 0;\n this.pendingBytes = 0;\n this.pendingMetadata.length = 0; // Emit the built segment\n // We include captions and ID3 tags for backwards compatibility,\n // ideally we should send only video and audio in the data event\n\n this.trigger('data', event); // Emit each caption to the outside world\n // Ideally, this would happen immediately on parsing captions,\n // but we need to ensure that video data is sent back first\n // so that caption timing can be adjusted to match video timing\n\n for (i = 0; i < event.captions.length; i++) {\n caption = event.captions[i];\n this.trigger('caption', caption);\n } // Emit each id3 tag to the outside world\n // Ideally, this would happen immediately on parsing the tag,\n // but we need to ensure that video data is sent back first\n // so that ID3 frame timing can be adjusted to match video timing\n\n\n for (i = 0; i < event.metadata.length; i++) {\n id3 = event.metadata[i];\n this.trigger('id3Frame', id3);\n }\n } // Only emit `done` if all tracks have been flushed and emitted\n\n\n if (this.emittedTracks >= this.numberOfTracks) {\n this.trigger('done');\n this.emittedTracks = 0;\n }\n };\n\n CoalesceStream.prototype.setRemux = function (val) {\n this.remuxTracks = val;\n };\n /**\n * A Stream that expects MP2T binary data as input and produces\n * corresponding media segments, suitable for use with Media Source\n * Extension (MSE) implementations that support the ISO BMFF byte\n * stream format, like Chrome.\n */\n\n\n Transmuxer = function (options) {\n var self = this,\n hasFlushed = true,\n videoTrack,\n audioTrack;\n Transmuxer.prototype.init.call(this);\n options = options || {};\n this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0;\n this.transmuxPipeline_ = {};\n\n this.setupAacPipeline = function () {\n var pipeline = {};\n this.transmuxPipeline_ = pipeline;\n pipeline.type = 'aac';\n pipeline.metadataStream = new m2ts.MetadataStream(); // set up the parsing pipeline\n\n pipeline.aacStream = new AacStream();\n pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');\n pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');\n pipeline.adtsStream = new AdtsStream();\n pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);\n pipeline.headOfPipeline = pipeline.aacStream;\n pipeline.aacStream.pipe(pipeline.audioTimestampRolloverStream).pipe(pipeline.adtsStream);\n pipeline.aacStream.pipe(pipeline.timedMetadataTimestampRolloverStream).pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream);\n pipeline.metadataStream.on('timestamp', function (frame) {\n pipeline.aacStream.setTimestamp(frame.timeStamp);\n });\n pipeline.aacStream.on('data', function (data) {\n if (data.type !== 'timed-metadata' && data.type !== 'audio' || pipeline.audioSegmentStream) {\n return;\n }\n\n audioTrack = audioTrack || {\n timelineStartInfo: {\n baseMediaDecodeTime: self.baseMediaDecodeTime\n },\n codec: 'adts',\n type: 'audio'\n }; // hook up the audio segment stream to the first track with aac data\n\n pipeline.coalesceStream.numberOfTracks++;\n pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack, options);\n pipeline.audioSegmentStream.on('log', self.getLogTrigger_('audioSegmentStream'));\n pipeline.audioSegmentStream.on('timingInfo', self.trigger.bind(self, 'audioTimingInfo')); // Set up the final part of the audio pipeline\n\n pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream); // emit pmt info\n\n self.trigger('trackinfo', {\n hasAudio: !!audioTrack,\n hasVideo: !!videoTrack\n });\n }); // Re-emit any data coming from the coalesce stream to the outside world\n\n pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data')); // Let the consumer know we have finished flushing the entire pipeline\n\n pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));\n addPipelineLogRetriggers(this, pipeline);\n };\n\n this.setupTsPipeline = function () {\n var pipeline = {};\n this.transmuxPipeline_ = pipeline;\n pipeline.type = 'ts';\n pipeline.metadataStream = new m2ts.MetadataStream(); // set up the parsing pipeline\n\n pipeline.packetStream = new m2ts.TransportPacketStream();\n pipeline.parseStream = new m2ts.TransportParseStream();\n pipeline.elementaryStream = new m2ts.ElementaryStream();\n pipeline.timestampRolloverStream = new m2ts.TimestampRolloverStream();\n pipeline.adtsStream = new AdtsStream();\n pipeline.h264Stream = new H264Stream();\n pipeline.captionStream = new m2ts.CaptionStream(options);\n pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);\n pipeline.headOfPipeline = pipeline.packetStream; // disassemble MPEG2-TS packets into elementary streams\n\n pipeline.packetStream.pipe(pipeline.parseStream).pipe(pipeline.elementaryStream).pipe(pipeline.timestampRolloverStream); // !!THIS ORDER IS IMPORTANT!!\n // demux the streams\n\n pipeline.timestampRolloverStream.pipe(pipeline.h264Stream);\n pipeline.timestampRolloverStream.pipe(pipeline.adtsStream);\n pipeline.timestampRolloverStream.pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream); // Hook up CEA-608/708 caption stream\n\n pipeline.h264Stream.pipe(pipeline.captionStream).pipe(pipeline.coalesceStream);\n pipeline.elementaryStream.on('data', function (data) {\n var i;\n\n if (data.type === 'metadata') {\n i = data.tracks.length; // scan the tracks listed in the metadata\n\n while (i--) {\n if (!videoTrack && data.tracks[i].type === 'video') {\n videoTrack = data.tracks[i];\n videoTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;\n } else if (!audioTrack && data.tracks[i].type === 'audio') {\n audioTrack = data.tracks[i];\n audioTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;\n }\n } // hook up the video segment stream to the first track with h264 data\n\n\n if (videoTrack && !pipeline.videoSegmentStream) {\n pipeline.coalesceStream.numberOfTracks++;\n pipeline.videoSegmentStream = new VideoSegmentStream(videoTrack, options);\n pipeline.videoSegmentStream.on('log', self.getLogTrigger_('videoSegmentStream'));\n pipeline.videoSegmentStream.on('timelineStartInfo', function (timelineStartInfo) {\n // When video emits timelineStartInfo data after a flush, we forward that\n // info to the AudioSegmentStream, if it exists, because video timeline\n // data takes precedence. Do not do this if keepOriginalTimestamps is set,\n // because this is a particularly subtle form of timestamp alteration.\n if (audioTrack && !options.keepOriginalTimestamps) {\n audioTrack.timelineStartInfo = timelineStartInfo; // On the first segment we trim AAC frames that exist before the\n // very earliest DTS we have seen in video because Chrome will\n // interpret any video track with a baseMediaDecodeTime that is\n // non-zero as a gap.\n\n pipeline.audioSegmentStream.setEarliestDts(timelineStartInfo.dts - self.baseMediaDecodeTime);\n }\n });\n pipeline.videoSegmentStream.on('processedGopsInfo', self.trigger.bind(self, 'gopInfo'));\n pipeline.videoSegmentStream.on('segmentTimingInfo', self.trigger.bind(self, 'videoSegmentTimingInfo'));\n pipeline.videoSegmentStream.on('baseMediaDecodeTime', function (baseMediaDecodeTime) {\n if (audioTrack) {\n pipeline.audioSegmentStream.setVideoBaseMediaDecodeTime(baseMediaDecodeTime);\n }\n });\n pipeline.videoSegmentStream.on('timingInfo', self.trigger.bind(self, 'videoTimingInfo')); // Set up the final part of the video pipeline\n\n pipeline.h264Stream.pipe(pipeline.videoSegmentStream).pipe(pipeline.coalesceStream);\n }\n\n if (audioTrack && !pipeline.audioSegmentStream) {\n // hook up the audio segment stream to the first track with aac data\n pipeline.coalesceStream.numberOfTracks++;\n pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack, options);\n pipeline.audioSegmentStream.on('log', self.getLogTrigger_('audioSegmentStream'));\n pipeline.audioSegmentStream.on('timingInfo', self.trigger.bind(self, 'audioTimingInfo'));\n pipeline.audioSegmentStream.on('segmentTimingInfo', self.trigger.bind(self, 'audioSegmentTimingInfo')); // Set up the final part of the audio pipeline\n\n pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream);\n } // emit pmt info\n\n\n self.trigger('trackinfo', {\n hasAudio: !!audioTrack,\n hasVideo: !!videoTrack\n });\n }\n }); // Re-emit any data coming from the coalesce stream to the outside world\n\n pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));\n pipeline.coalesceStream.on('id3Frame', function (id3Frame) {\n id3Frame.dispatchType = pipeline.metadataStream.dispatchType;\n self.trigger('id3Frame', id3Frame);\n });\n pipeline.coalesceStream.on('caption', this.trigger.bind(this, 'caption')); // Let the consumer know we have finished flushing the entire pipeline\n\n pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));\n addPipelineLogRetriggers(this, pipeline);\n }; // hook up the segment streams once track metadata is delivered\n\n\n this.setBaseMediaDecodeTime = function (baseMediaDecodeTime) {\n var pipeline = this.transmuxPipeline_;\n\n if (!options.keepOriginalTimestamps) {\n this.baseMediaDecodeTime = baseMediaDecodeTime;\n }\n\n if (audioTrack) {\n audioTrack.timelineStartInfo.dts = undefined;\n audioTrack.timelineStartInfo.pts = undefined;\n trackDecodeInfo.clearDtsInfo(audioTrack);\n\n if (pipeline.audioTimestampRolloverStream) {\n pipeline.audioTimestampRolloverStream.discontinuity();\n }\n }\n\n if (videoTrack) {\n if (pipeline.videoSegmentStream) {\n pipeline.videoSegmentStream.gopCache_ = [];\n }\n\n videoTrack.timelineStartInfo.dts = undefined;\n videoTrack.timelineStartInfo.pts = undefined;\n trackDecodeInfo.clearDtsInfo(videoTrack);\n pipeline.captionStream.reset();\n }\n\n if (pipeline.timestampRolloverStream) {\n pipeline.timestampRolloverStream.discontinuity();\n }\n };\n\n this.setAudioAppendStart = function (timestamp) {\n if (audioTrack) {\n this.transmuxPipeline_.audioSegmentStream.setAudioAppendStart(timestamp);\n }\n };\n\n this.setRemux = function (val) {\n var pipeline = this.transmuxPipeline_;\n options.remux = val;\n\n if (pipeline && pipeline.coalesceStream) {\n pipeline.coalesceStream.setRemux(val);\n }\n };\n\n this.alignGopsWith = function (gopsToAlignWith) {\n if (videoTrack && this.transmuxPipeline_.videoSegmentStream) {\n this.transmuxPipeline_.videoSegmentStream.alignGopsWith(gopsToAlignWith);\n }\n };\n\n this.getLogTrigger_ = function (key) {\n var self = this;\n return function (event) {\n event.stream = key;\n self.trigger('log', event);\n };\n }; // feed incoming data to the front of the parsing pipeline\n\n\n this.push = function (data) {\n if (hasFlushed) {\n var isAac = isLikelyAacData(data);\n\n if (isAac && this.transmuxPipeline_.type !== 'aac') {\n this.setupAacPipeline();\n } else if (!isAac && this.transmuxPipeline_.type !== 'ts') {\n this.setupTsPipeline();\n }\n\n hasFlushed = false;\n }\n\n this.transmuxPipeline_.headOfPipeline.push(data);\n }; // flush any buffered data\n\n\n this.flush = function () {\n hasFlushed = true; // Start at the top of the pipeline and flush all pending work\n\n this.transmuxPipeline_.headOfPipeline.flush();\n };\n\n this.endTimeline = function () {\n this.transmuxPipeline_.headOfPipeline.endTimeline();\n };\n\n this.reset = function () {\n if (this.transmuxPipeline_.headOfPipeline) {\n this.transmuxPipeline_.headOfPipeline.reset();\n }\n }; // Caption data has to be reset when seeking outside buffered range\n\n\n this.resetCaptions = function () {\n if (this.transmuxPipeline_.captionStream) {\n this.transmuxPipeline_.captionStream.reset();\n }\n };\n };\n\n Transmuxer.prototype = new Stream();\n var transmuxer = {\n Transmuxer: Transmuxer,\n VideoSegmentStream: VideoSegmentStream,\n AudioSegmentStream: AudioSegmentStream,\n AUDIO_PROPERTIES: AUDIO_PROPERTIES,\n VIDEO_PROPERTIES: VIDEO_PROPERTIES,\n // exported for testing\n generateSegmentTimingInfo: generateSegmentTimingInfo\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n */\n\n var toUnsigned$3 = function (value) {\n return value >>> 0;\n };\n\n var toHexString$1 = function (value) {\n return ('00' + value.toString(16)).slice(-2);\n };\n\n var bin = {\n toUnsigned: toUnsigned$3,\n toHexString: toHexString$1\n };\n\n var parseType$4 = function (buffer) {\n var result = '';\n result += String.fromCharCode(buffer[0]);\n result += String.fromCharCode(buffer[1]);\n result += String.fromCharCode(buffer[2]);\n result += String.fromCharCode(buffer[3]);\n return result;\n };\n\n var parseType_1 = parseType$4;\n var toUnsigned$2 = bin.toUnsigned;\n var parseType$3 = parseType_1;\n\n var findBox$5 = function (data, path) {\n var results = [],\n i,\n size,\n type,\n end,\n subresults;\n\n if (!path.length) {\n // short-circuit the search for empty paths\n return null;\n }\n\n for (i = 0; i < data.byteLength;) {\n size = toUnsigned$2(data[i] << 24 | data[i + 1] << 16 | data[i + 2] << 8 | data[i + 3]);\n type = parseType$3(data.subarray(i + 4, i + 8));\n end = size > 1 ? i + size : data.byteLength;\n\n if (type === path[0]) {\n if (path.length === 1) {\n // this is the end of the path and we've found the box we were\n // looking for\n results.push(data.subarray(i + 8, end));\n } else {\n // recursively search for the next box along the path\n subresults = findBox$5(data.subarray(i + 8, end), path.slice(1));\n\n if (subresults.length) {\n results = results.concat(subresults);\n }\n }\n }\n\n i = end;\n } // we've finished searching all of data\n\n\n return results;\n };\n\n var findBox_1 = findBox$5;\n var toUnsigned$1 = bin.toUnsigned;\n var getUint64$4 = numbers.getUint64;\n\n var tfdt = function (data) {\n var result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4))\n };\n\n if (result.version === 1) {\n result.baseMediaDecodeTime = getUint64$4(data.subarray(4));\n } else {\n result.baseMediaDecodeTime = toUnsigned$1(data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]);\n }\n\n return result;\n };\n\n var parseTfdt$3 = tfdt;\n\n var tfhd = function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n trackId: view.getUint32(4)\n },\n baseDataOffsetPresent = result.flags[2] & 0x01,\n sampleDescriptionIndexPresent = result.flags[2] & 0x02,\n defaultSampleDurationPresent = result.flags[2] & 0x08,\n defaultSampleSizePresent = result.flags[2] & 0x10,\n defaultSampleFlagsPresent = result.flags[2] & 0x20,\n durationIsEmpty = result.flags[0] & 0x010000,\n defaultBaseIsMoof = result.flags[0] & 0x020000,\n i;\n i = 8;\n\n if (baseDataOffsetPresent) {\n i += 4; // truncate top 4 bytes\n // FIXME: should we read the full 64 bits?\n\n result.baseDataOffset = view.getUint32(12);\n i += 4;\n }\n\n if (sampleDescriptionIndexPresent) {\n result.sampleDescriptionIndex = view.getUint32(i);\n i += 4;\n }\n\n if (defaultSampleDurationPresent) {\n result.defaultSampleDuration = view.getUint32(i);\n i += 4;\n }\n\n if (defaultSampleSizePresent) {\n result.defaultSampleSize = view.getUint32(i);\n i += 4;\n }\n\n if (defaultSampleFlagsPresent) {\n result.defaultSampleFlags = view.getUint32(i);\n }\n\n if (durationIsEmpty) {\n result.durationIsEmpty = true;\n }\n\n if (!baseDataOffsetPresent && defaultBaseIsMoof) {\n result.baseDataOffsetIsMoof = true;\n }\n\n return result;\n };\n\n var parseTfhd$2 = tfhd;\n var getUint64$3 = numbers.getUint64;\n\n var parseSidx = function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n references: [],\n referenceId: view.getUint32(4),\n timescale: view.getUint32(8)\n },\n i = 12;\n\n if (result.version === 0) {\n result.earliestPresentationTime = view.getUint32(i);\n result.firstOffset = view.getUint32(i + 4);\n i += 8;\n } else {\n // read 64 bits\n result.earliestPresentationTime = getUint64$3(data.subarray(i));\n result.firstOffset = getUint64$3(data.subarray(i + 8));\n i += 16;\n }\n\n i += 2; // reserved\n\n var referenceCount = view.getUint16(i);\n i += 2; // start of references\n\n for (; referenceCount > 0; i += 12, referenceCount--) {\n result.references.push({\n referenceType: (data[i] & 0x80) >>> 7,\n referencedSize: view.getUint32(i) & 0x7FFFFFFF,\n subsegmentDuration: view.getUint32(i + 4),\n startsWithSap: !!(data[i + 8] & 0x80),\n sapType: (data[i + 8] & 0x70) >>> 4,\n sapDeltaTime: view.getUint32(i + 8) & 0x0FFFFFFF\n });\n }\n\n return result;\n };\n\n var parseSidx_1 = parseSidx;\n\n var parseSampleFlags$1 = function (flags) {\n return {\n isLeading: (flags[0] & 0x0c) >>> 2,\n dependsOn: flags[0] & 0x03,\n isDependedOn: (flags[1] & 0xc0) >>> 6,\n hasRedundancy: (flags[1] & 0x30) >>> 4,\n paddingValue: (flags[1] & 0x0e) >>> 1,\n isNonSyncSample: flags[1] & 0x01,\n degradationPriority: flags[2] << 8 | flags[3]\n };\n };\n\n var parseSampleFlags_1 = parseSampleFlags$1;\n var parseSampleFlags = parseSampleFlags_1;\n\n var trun = function (data) {\n var result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n samples: []\n },\n view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n // Flag interpretation\n dataOffsetPresent = result.flags[2] & 0x01,\n // compare with 2nd byte of 0x1\n firstSampleFlagsPresent = result.flags[2] & 0x04,\n // compare with 2nd byte of 0x4\n sampleDurationPresent = result.flags[1] & 0x01,\n // compare with 2nd byte of 0x100\n sampleSizePresent = result.flags[1] & 0x02,\n // compare with 2nd byte of 0x200\n sampleFlagsPresent = result.flags[1] & 0x04,\n // compare with 2nd byte of 0x400\n sampleCompositionTimeOffsetPresent = result.flags[1] & 0x08,\n // compare with 2nd byte of 0x800\n sampleCount = view.getUint32(4),\n offset = 8,\n sample;\n\n if (dataOffsetPresent) {\n // 32 bit signed integer\n result.dataOffset = view.getInt32(offset);\n offset += 4;\n } // Overrides the flags for the first sample only. The order of\n // optional values will be: duration, size, compositionTimeOffset\n\n\n if (firstSampleFlagsPresent && sampleCount) {\n sample = {\n flags: parseSampleFlags(data.subarray(offset, offset + 4))\n };\n offset += 4;\n\n if (sampleDurationPresent) {\n sample.duration = view.getUint32(offset);\n offset += 4;\n }\n\n if (sampleSizePresent) {\n sample.size = view.getUint32(offset);\n offset += 4;\n }\n\n if (sampleCompositionTimeOffsetPresent) {\n if (result.version === 1) {\n sample.compositionTimeOffset = view.getInt32(offset);\n } else {\n sample.compositionTimeOffset = view.getUint32(offset);\n }\n\n offset += 4;\n }\n\n result.samples.push(sample);\n sampleCount--;\n }\n\n while (sampleCount--) {\n sample = {};\n\n if (sampleDurationPresent) {\n sample.duration = view.getUint32(offset);\n offset += 4;\n }\n\n if (sampleSizePresent) {\n sample.size = view.getUint32(offset);\n offset += 4;\n }\n\n if (sampleFlagsPresent) {\n sample.flags = parseSampleFlags(data.subarray(offset, offset + 4));\n offset += 4;\n }\n\n if (sampleCompositionTimeOffsetPresent) {\n if (result.version === 1) {\n sample.compositionTimeOffset = view.getInt32(offset);\n } else {\n sample.compositionTimeOffset = view.getUint32(offset);\n }\n\n offset += 4;\n }\n\n result.samples.push(sample);\n }\n\n return result;\n };\n\n var parseTrun$2 = trun;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Parse the internal MP4 structure into an equivalent javascript\n * object.\n */\n\n var numberHelpers = numbers;\n var getUint64$2 = numberHelpers.getUint64;\n\n var inspectMp4,\n textifyMp4,\n parseMp4Date = function (seconds) {\n return new Date(seconds * 1000 - 2082844800000);\n },\n parseType$2 = parseType_1,\n findBox$4 = findBox_1,\n nalParse = function (avcStream) {\n var avcView = new DataView(avcStream.buffer, avcStream.byteOffset, avcStream.byteLength),\n result = [],\n i,\n length;\n\n for (i = 0; i + 4 < avcStream.length; i += length) {\n length = avcView.getUint32(i);\n i += 4; // bail if this doesn't appear to be an H264 stream\n\n if (length <= 0) {\n result.push('MALFORMED DATA');\n continue;\n }\n\n switch (avcStream[i] & 0x1F) {\n case 0x01:\n result.push('slice_layer_without_partitioning_rbsp');\n break;\n\n case 0x05:\n result.push('slice_layer_without_partitioning_rbsp_idr');\n break;\n\n case 0x06:\n result.push('sei_rbsp');\n break;\n\n case 0x07:\n result.push('seq_parameter_set_rbsp');\n break;\n\n case 0x08:\n result.push('pic_parameter_set_rbsp');\n break;\n\n case 0x09:\n result.push('access_unit_delimiter_rbsp');\n break;\n\n default:\n result.push('UNKNOWN NAL - ' + avcStream[i] & 0x1F);\n break;\n }\n }\n\n return result;\n },\n // registry of handlers for individual mp4 box types\n parse = {\n // codingname, not a first-class box type. stsd entries share the\n // same format as real boxes so the parsing infrastructure can be\n // shared\n avc1: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n dataReferenceIndex: view.getUint16(6),\n width: view.getUint16(24),\n height: view.getUint16(26),\n horizresolution: view.getUint16(28) + view.getUint16(30) / 16,\n vertresolution: view.getUint16(32) + view.getUint16(34) / 16,\n frameCount: view.getUint16(40),\n depth: view.getUint16(74),\n config: inspectMp4(data.subarray(78, data.byteLength))\n };\n },\n avcC: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n configurationVersion: data[0],\n avcProfileIndication: data[1],\n profileCompatibility: data[2],\n avcLevelIndication: data[3],\n lengthSizeMinusOne: data[4] & 0x03,\n sps: [],\n pps: []\n },\n numOfSequenceParameterSets = data[5] & 0x1f,\n numOfPictureParameterSets,\n nalSize,\n offset,\n i; // iterate past any SPSs\n\n offset = 6;\n\n for (i = 0; i < numOfSequenceParameterSets; i++) {\n nalSize = view.getUint16(offset);\n offset += 2;\n result.sps.push(new Uint8Array(data.subarray(offset, offset + nalSize)));\n offset += nalSize;\n } // iterate past any PPSs\n\n\n numOfPictureParameterSets = data[offset];\n offset++;\n\n for (i = 0; i < numOfPictureParameterSets; i++) {\n nalSize = view.getUint16(offset);\n offset += 2;\n result.pps.push(new Uint8Array(data.subarray(offset, offset + nalSize)));\n offset += nalSize;\n }\n\n return result;\n },\n btrt: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n bufferSizeDB: view.getUint32(0),\n maxBitrate: view.getUint32(4),\n avgBitrate: view.getUint32(8)\n };\n },\n edts: function edts(data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n elst: function elst(data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n edits: []\n },\n entryCount = view.getUint32(4),\n i;\n\n for (i = 8; entryCount; entryCount--) {\n if (result.version === 0) {\n result.edits.push({\n segmentDuration: view.getUint32(i),\n mediaTime: view.getInt32(i + 4),\n mediaRate: view.getUint16(i + 8) + view.getUint16(i + 10) / (256 * 256)\n });\n i += 12;\n } else {\n result.edits.push({\n segmentDuration: getUint64$2(data.subarray(i)),\n mediaTime: getUint64$2(data.subarray(i + 8)),\n mediaRate: view.getUint16(i + 16) + view.getUint16(i + 18) / (256 * 256)\n });\n i += 20;\n }\n }\n\n return result;\n },\n esds: function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n esId: data[6] << 8 | data[7],\n streamPriority: data[8] & 0x1f,\n decoderConfig: {\n objectProfileIndication: data[11],\n streamType: data[12] >>> 2 & 0x3f,\n bufferSize: data[13] << 16 | data[14] << 8 | data[15],\n maxBitrate: data[16] << 24 | data[17] << 16 | data[18] << 8 | data[19],\n avgBitrate: data[20] << 24 | data[21] << 16 | data[22] << 8 | data[23],\n decoderConfigDescriptor: {\n tag: data[24],\n length: data[25],\n audioObjectType: data[26] >>> 3 & 0x1f,\n samplingFrequencyIndex: (data[26] & 0x07) << 1 | data[27] >>> 7 & 0x01,\n channelConfiguration: data[27] >>> 3 & 0x0f\n }\n }\n };\n },\n ftyp: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n majorBrand: parseType$2(data.subarray(0, 4)),\n minorVersion: view.getUint32(4),\n compatibleBrands: []\n },\n i = 8;\n\n while (i < data.byteLength) {\n result.compatibleBrands.push(parseType$2(data.subarray(i, i + 4)));\n i += 4;\n }\n\n return result;\n },\n dinf: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n dref: function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n dataReferences: inspectMp4(data.subarray(8))\n };\n },\n hdlr: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n handlerType: parseType$2(data.subarray(8, 12)),\n name: ''\n },\n i = 8; // parse out the name field\n\n for (i = 24; i < data.byteLength; i++) {\n if (data[i] === 0x00) {\n // the name field is null-terminated\n i++;\n break;\n }\n\n result.name += String.fromCharCode(data[i]);\n } // decode UTF-8 to javascript's internal representation\n // see http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html\n\n\n result.name = decodeURIComponent(escape(result.name));\n return result;\n },\n mdat: function (data) {\n return {\n byteLength: data.byteLength,\n nals: nalParse(data)\n };\n },\n mdhd: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n i = 4,\n language,\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n language: ''\n };\n\n if (result.version === 1) {\n i += 4;\n result.creationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 8;\n result.modificationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 4;\n result.timescale = view.getUint32(i);\n i += 8;\n result.duration = view.getUint32(i); // truncating top 4 bytes\n } else {\n result.creationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.modificationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.timescale = view.getUint32(i);\n i += 4;\n result.duration = view.getUint32(i);\n }\n\n i += 4; // language is stored as an ISO-639-2/T code in an array of three 5-bit fields\n // each field is the packed difference between its ASCII value and 0x60\n\n language = view.getUint16(i);\n result.language += String.fromCharCode((language >> 10) + 0x60);\n result.language += String.fromCharCode(((language & 0x03e0) >> 5) + 0x60);\n result.language += String.fromCharCode((language & 0x1f) + 0x60);\n return result;\n },\n mdia: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n mfhd: function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n sequenceNumber: data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]\n };\n },\n minf: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n // codingname, not a first-class box type. stsd entries share the\n // same format as real boxes so the parsing infrastructure can be\n // shared\n mp4a: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n // 6 bytes reserved\n dataReferenceIndex: view.getUint16(6),\n // 4 + 4 bytes reserved\n channelcount: view.getUint16(16),\n samplesize: view.getUint16(18),\n // 2 bytes pre_defined\n // 2 bytes reserved\n samplerate: view.getUint16(24) + view.getUint16(26) / 65536\n }; // if there are more bytes to process, assume this is an ISO/IEC\n // 14496-14 MP4AudioSampleEntry and parse the ESDBox\n\n if (data.byteLength > 28) {\n result.streamDescriptor = inspectMp4(data.subarray(28))[0];\n }\n\n return result;\n },\n moof: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n moov: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n mvex: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n mvhd: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n i = 4,\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4))\n };\n\n if (result.version === 1) {\n i += 4;\n result.creationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 8;\n result.modificationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 4;\n result.timescale = view.getUint32(i);\n i += 8;\n result.duration = view.getUint32(i); // truncating top 4 bytes\n } else {\n result.creationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.modificationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.timescale = view.getUint32(i);\n i += 4;\n result.duration = view.getUint32(i);\n }\n\n i += 4; // convert fixed-point, base 16 back to a number\n\n result.rate = view.getUint16(i) + view.getUint16(i + 2) / 16;\n i += 4;\n result.volume = view.getUint8(i) + view.getUint8(i + 1) / 8;\n i += 2;\n i += 2;\n i += 2 * 4;\n result.matrix = new Uint32Array(data.subarray(i, i + 9 * 4));\n i += 9 * 4;\n i += 6 * 4;\n result.nextTrackId = view.getUint32(i);\n return result;\n },\n pdin: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n rate: view.getUint32(4),\n initialDelay: view.getUint32(8)\n };\n },\n sdtp: function (data) {\n var result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n samples: []\n },\n i;\n\n for (i = 4; i < data.byteLength; i++) {\n result.samples.push({\n dependsOn: (data[i] & 0x30) >> 4,\n isDependedOn: (data[i] & 0x0c) >> 2,\n hasRedundancy: data[i] & 0x03\n });\n }\n\n return result;\n },\n sidx: parseSidx_1,\n smhd: function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n balance: data[4] + data[5] / 256\n };\n },\n stbl: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n ctts: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n compositionOffsets: []\n },\n entryCount = view.getUint32(4),\n i;\n\n for (i = 8; entryCount; i += 8, entryCount--) {\n result.compositionOffsets.push({\n sampleCount: view.getUint32(i),\n sampleOffset: view[result.version === 0 ? 'getUint32' : 'getInt32'](i + 4)\n });\n }\n\n return result;\n },\n stss: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4)),\n syncSamples: []\n },\n entryCount = view.getUint32(4),\n i;\n\n for (i = 8; entryCount; i += 4, entryCount--) {\n result.syncSamples.push(view.getUint32(i));\n }\n\n return result;\n },\n stco: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n chunkOffsets: []\n },\n entryCount = view.getUint32(4),\n i;\n\n for (i = 8; entryCount; i += 4, entryCount--) {\n result.chunkOffsets.push(view.getUint32(i));\n }\n\n return result;\n },\n stsc: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n entryCount = view.getUint32(4),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n sampleToChunks: []\n },\n i;\n\n for (i = 8; entryCount; i += 12, entryCount--) {\n result.sampleToChunks.push({\n firstChunk: view.getUint32(i),\n samplesPerChunk: view.getUint32(i + 4),\n sampleDescriptionIndex: view.getUint32(i + 8)\n });\n }\n\n return result;\n },\n stsd: function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n sampleDescriptions: inspectMp4(data.subarray(8))\n };\n },\n stsz: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n sampleSize: view.getUint32(4),\n entries: []\n },\n i;\n\n for (i = 12; i < data.byteLength; i += 4) {\n result.entries.push(view.getUint32(i));\n }\n\n return result;\n },\n stts: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n result = {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n timeToSamples: []\n },\n entryCount = view.getUint32(4),\n i;\n\n for (i = 8; entryCount; i += 8, entryCount--) {\n result.timeToSamples.push({\n sampleCount: view.getUint32(i),\n sampleDelta: view.getUint32(i + 4)\n });\n }\n\n return result;\n },\n styp: function (data) {\n return parse.ftyp(data);\n },\n tfdt: parseTfdt$3,\n tfhd: parseTfhd$2,\n tkhd: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength),\n i = 4,\n result = {\n version: view.getUint8(0),\n flags: new Uint8Array(data.subarray(1, 4))\n };\n\n if (result.version === 1) {\n i += 4;\n result.creationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 8;\n result.modificationTime = parseMp4Date(view.getUint32(i)); // truncating top 4 bytes\n\n i += 4;\n result.trackId = view.getUint32(i);\n i += 4;\n i += 8;\n result.duration = view.getUint32(i); // truncating top 4 bytes\n } else {\n result.creationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.modificationTime = parseMp4Date(view.getUint32(i));\n i += 4;\n result.trackId = view.getUint32(i);\n i += 4;\n i += 4;\n result.duration = view.getUint32(i);\n }\n\n i += 4;\n i += 2 * 4;\n result.layer = view.getUint16(i);\n i += 2;\n result.alternateGroup = view.getUint16(i);\n i += 2; // convert fixed-point, base 16 back to a number\n\n result.volume = view.getUint8(i) + view.getUint8(i + 1) / 8;\n i += 2;\n i += 2;\n result.matrix = new Uint32Array(data.subarray(i, i + 9 * 4));\n i += 9 * 4;\n result.width = view.getUint16(i) + view.getUint16(i + 2) / 65536;\n i += 4;\n result.height = view.getUint16(i) + view.getUint16(i + 2) / 65536;\n return result;\n },\n traf: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n trak: function (data) {\n return {\n boxes: inspectMp4(data)\n };\n },\n trex: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n trackId: view.getUint32(4),\n defaultSampleDescriptionIndex: view.getUint32(8),\n defaultSampleDuration: view.getUint32(12),\n defaultSampleSize: view.getUint32(16),\n sampleDependsOn: data[20] & 0x03,\n sampleIsDependedOn: (data[21] & 0xc0) >> 6,\n sampleHasRedundancy: (data[21] & 0x30) >> 4,\n samplePaddingValue: (data[21] & 0x0e) >> 1,\n sampleIsDifferenceSample: !!(data[21] & 0x01),\n sampleDegradationPriority: view.getUint16(22)\n };\n },\n trun: parseTrun$2,\n 'url ': function (data) {\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4))\n };\n },\n vmhd: function (data) {\n var view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return {\n version: data[0],\n flags: new Uint8Array(data.subarray(1, 4)),\n graphicsmode: view.getUint16(4),\n opcolor: new Uint16Array([view.getUint16(6), view.getUint16(8), view.getUint16(10)])\n };\n }\n };\n /**\n * Return a javascript array of box objects parsed from an ISO base\n * media file.\n * @param data {Uint8Array} the binary data of the media to be inspected\n * @return {array} a javascript array of potentially nested box objects\n */\n\n\n inspectMp4 = function (data) {\n var i = 0,\n result = [],\n view,\n size,\n type,\n end,\n box; // Convert data from Uint8Array to ArrayBuffer, to follow Dataview API\n\n var ab = new ArrayBuffer(data.length);\n var v = new Uint8Array(ab);\n\n for (var z = 0; z < data.length; ++z) {\n v[z] = data[z];\n }\n\n view = new DataView(ab);\n\n while (i < data.byteLength) {\n // parse box data\n size = view.getUint32(i);\n type = parseType$2(data.subarray(i + 4, i + 8));\n end = size > 1 ? i + size : data.byteLength; // parse type-specific data\n\n box = (parse[type] || function (data) {\n return {\n data: data\n };\n })(data.subarray(i + 8, end));\n\n box.size = size;\n box.type = type; // store this box and move to the next\n\n result.push(box);\n i = end;\n }\n\n return result;\n };\n /**\n * Returns a textual representation of the javascript represtentation\n * of an MP4 file. You can use it as an alternative to\n * JSON.stringify() to compare inspected MP4s.\n * @param inspectedMp4 {array} the parsed array of boxes in an MP4\n * file\n * @param depth {number} (optional) the number of ancestor boxes of\n * the elements of inspectedMp4. Assumed to be zero if unspecified.\n * @return {string} a text representation of the parsed MP4\n */\n\n\n textifyMp4 = function (inspectedMp4, depth) {\n var indent;\n depth = depth || 0;\n indent = new Array(depth * 2 + 1).join(' '); // iterate over all the boxes\n\n return inspectedMp4.map(function (box, index) {\n // list the box type first at the current indentation level\n return indent + box.type + '\\n' + // the type is already included and handle child boxes separately\n Object.keys(box).filter(function (key) {\n return key !== 'type' && key !== 'boxes'; // output all the box properties\n }).map(function (key) {\n var prefix = indent + ' ' + key + ': ',\n value = box[key]; // print out raw bytes as hexademical\n\n if (value instanceof Uint8Array || value instanceof Uint32Array) {\n var bytes = Array.prototype.slice.call(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)).map(function (byte) {\n return ' ' + ('00' + byte.toString(16)).slice(-2);\n }).join('').match(/.{1,24}/g);\n\n if (!bytes) {\n return prefix + '<>';\n }\n\n if (bytes.length === 1) {\n return prefix + '<' + bytes.join('').slice(1) + '>';\n }\n\n return prefix + '<\\n' + bytes.map(function (line) {\n return indent + ' ' + line;\n }).join('\\n') + '\\n' + indent + ' >';\n } // stringify generic objects\n\n\n return prefix + JSON.stringify(value, null, 2).split('\\n').map(function (line, index) {\n if (index === 0) {\n return line;\n }\n\n return indent + ' ' + line;\n }).join('\\n');\n }).join('\\n') + ( // recursively textify the child boxes\n box.boxes ? '\\n' + textifyMp4(box.boxes, depth + 1) : '');\n }).join('\\n');\n };\n\n var mp4Inspector = {\n inspect: inspectMp4,\n textify: textifyMp4,\n parseType: parseType$2,\n findBox: findBox$4,\n parseTraf: parse.traf,\n parseTfdt: parse.tfdt,\n parseHdlr: parse.hdlr,\n parseTfhd: parse.tfhd,\n parseTrun: parse.trun,\n parseSidx: parse.sidx\n };\n /**\n * Returns the first string in the data array ending with a null char '\\0'\n * @param {UInt8} data \n * @returns the string with the null char\n */\n\n var uint8ToCString$1 = function (data) {\n var index = 0;\n var curChar = String.fromCharCode(data[index]);\n var retString = '';\n\n while (curChar !== '\\0') {\n retString += curChar;\n index++;\n curChar = String.fromCharCode(data[index]);\n } // Add nullChar\n\n\n retString += curChar;\n return retString;\n };\n\n var string = {\n uint8ToCString: uint8ToCString$1\n };\n var uint8ToCString = string.uint8ToCString;\n var getUint64$1 = numbers.getUint64;\n /**\n * Based on: ISO/IEC 23009 Section: 5.10.3.3\n * References:\n * https://dashif-documents.azurewebsites.net/Events/master/event.html#emsg-format\n * https://aomediacodec.github.io/id3-emsg/\n * \n * Takes emsg box data as a uint8 array and returns a emsg box object\n * @param {UInt8Array} boxData data from emsg box\n * @returns A parsed emsg box object\n */\n\n var parseEmsgBox = function (boxData) {\n // version + flags\n var offset = 4;\n var version = boxData[0];\n var scheme_id_uri, value, timescale, presentation_time, presentation_time_delta, event_duration, id, message_data;\n\n if (version === 0) {\n scheme_id_uri = uint8ToCString(boxData.subarray(offset));\n offset += scheme_id_uri.length;\n value = uint8ToCString(boxData.subarray(offset));\n offset += value.length;\n var dv = new DataView(boxData.buffer);\n timescale = dv.getUint32(offset);\n offset += 4;\n presentation_time_delta = dv.getUint32(offset);\n offset += 4;\n event_duration = dv.getUint32(offset);\n offset += 4;\n id = dv.getUint32(offset);\n offset += 4;\n } else if (version === 1) {\n var dv = new DataView(boxData.buffer);\n timescale = dv.getUint32(offset);\n offset += 4;\n presentation_time = getUint64$1(boxData.subarray(offset));\n offset += 8;\n event_duration = dv.getUint32(offset);\n offset += 4;\n id = dv.getUint32(offset);\n offset += 4;\n scheme_id_uri = uint8ToCString(boxData.subarray(offset));\n offset += scheme_id_uri.length;\n value = uint8ToCString(boxData.subarray(offset));\n offset += value.length;\n }\n\n message_data = new Uint8Array(boxData.subarray(offset, boxData.byteLength));\n var emsgBox = {\n scheme_id_uri,\n value,\n // if timescale is undefined or 0 set to 1 \n timescale: timescale ? timescale : 1,\n presentation_time,\n presentation_time_delta,\n event_duration,\n id,\n message_data\n };\n return isValidEmsgBox(version, emsgBox) ? emsgBox : undefined;\n };\n /**\n * Scales a presentation time or time delta with an offset with a provided timescale\n * @param {number} presentationTime \n * @param {number} timescale \n * @param {number} timeDelta \n * @param {number} offset \n * @returns the scaled time as a number\n */\n\n\n var scaleTime = function (presentationTime, timescale, timeDelta, offset) {\n return presentationTime || presentationTime === 0 ? presentationTime / timescale : offset + timeDelta / timescale;\n };\n /**\n * Checks the emsg box data for validity based on the version\n * @param {number} version of the emsg box to validate\n * @param {Object} emsg the emsg data to validate\n * @returns if the box is valid as a boolean\n */\n\n\n var isValidEmsgBox = function (version, emsg) {\n var hasScheme = emsg.scheme_id_uri !== '\\0';\n var isValidV0Box = version === 0 && isDefined(emsg.presentation_time_delta) && hasScheme;\n var isValidV1Box = version === 1 && isDefined(emsg.presentation_time) && hasScheme; // Only valid versions of emsg are 0 and 1\n\n return !(version > 1) && isValidV0Box || isValidV1Box;\n }; // Utility function to check if an object is defined\n\n\n var isDefined = function (data) {\n return data !== undefined || data !== null;\n };\n\n var emsg$1 = {\n parseEmsgBox: parseEmsgBox,\n scaleTime: scaleTime\n };\n var win;\n\n if (typeof window !== \"undefined\") {\n win = window;\n } else if (typeof commonjsGlobal !== \"undefined\") {\n win = commonjsGlobal;\n } else if (typeof self !== \"undefined\") {\n win = self;\n } else {\n win = {};\n }\n\n var window_1 = win;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Utilities to detect basic properties and metadata about MP4s.\n */\n\n var toUnsigned = bin.toUnsigned;\n var toHexString = bin.toHexString;\n var findBox$3 = findBox_1;\n var parseType$1 = parseType_1;\n var emsg = emsg$1;\n var parseTfhd$1 = parseTfhd$2;\n var parseTrun$1 = parseTrun$2;\n var parseTfdt$2 = parseTfdt$3;\n var getUint64 = numbers.getUint64;\n var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader$1, getEmsgID3;\n var window$2 = window_1;\n var parseId3Frames = parseId3.parseId3Frames;\n /**\n * Parses an MP4 initialization segment and extracts the timescale\n * values for any declared tracks. Timescale values indicate the\n * number of clock ticks per second to assume for time-based values\n * elsewhere in the MP4.\n *\n * To determine the start time of an MP4, you need two pieces of\n * information: the timescale unit and the earliest base media decode\n * time. Multiple timescales can be specified within an MP4 but the\n * base media decode time is always expressed in the timescale from\n * the media header box for the track:\n * ```\n * moov > trak > mdia > mdhd.timescale\n * ```\n * @param init {Uint8Array} the bytes of the init segment\n * @return {object} a hash of track ids to timescale values or null if\n * the init segment is malformed.\n */\n\n timescale = function (init) {\n var result = {},\n traks = findBox$3(init, ['moov', 'trak']); // mdhd timescale\n\n return traks.reduce(function (result, trak) {\n var tkhd, version, index, id, mdhd;\n tkhd = findBox$3(trak, ['tkhd'])[0];\n\n if (!tkhd) {\n return null;\n }\n\n version = tkhd[0];\n index = version === 0 ? 12 : 20;\n id = toUnsigned(tkhd[index] << 24 | tkhd[index + 1] << 16 | tkhd[index + 2] << 8 | tkhd[index + 3]);\n mdhd = findBox$3(trak, ['mdia', 'mdhd'])[0];\n\n if (!mdhd) {\n return null;\n }\n\n version = mdhd[0];\n index = version === 0 ? 12 : 20;\n result[id] = toUnsigned(mdhd[index] << 24 | mdhd[index + 1] << 16 | mdhd[index + 2] << 8 | mdhd[index + 3]);\n return result;\n }, result);\n };\n /**\n * Determine the base media decode start time, in seconds, for an MP4\n * fragment. If multiple fragments are specified, the earliest time is\n * returned.\n *\n * The base media decode time can be parsed from track fragment\n * metadata:\n * ```\n * moof > traf > tfdt.baseMediaDecodeTime\n * ```\n * It requires the timescale value from the mdhd to interpret.\n *\n * @param timescale {object} a hash of track ids to timescale values.\n * @return {number} the earliest base media decode start time for the\n * fragment, in seconds\n */\n\n\n startTime = function (timescale, fragment) {\n var trafs; // we need info from two childrend of each track fragment box\n\n trafs = findBox$3(fragment, ['moof', 'traf']); // determine the start times for each track\n\n var lowestTime = trafs.reduce(function (acc, traf) {\n var tfhd = findBox$3(traf, ['tfhd'])[0]; // get the track id from the tfhd\n\n var id = toUnsigned(tfhd[4] << 24 | tfhd[5] << 16 | tfhd[6] << 8 | tfhd[7]); // assume a 90kHz clock if no timescale was specified\n\n var scale = timescale[id] || 90e3; // get the base media decode time from the tfdt\n\n var tfdt = findBox$3(traf, ['tfdt'])[0];\n var dv = new DataView(tfdt.buffer, tfdt.byteOffset, tfdt.byteLength);\n var baseTime; // version 1 is 64 bit\n\n if (tfdt[0] === 1) {\n baseTime = getUint64(tfdt.subarray(4, 12));\n } else {\n baseTime = dv.getUint32(4);\n } // convert base time to seconds if it is a valid number.\n\n\n let seconds;\n\n if (typeof baseTime === 'bigint') {\n seconds = baseTime / window$2.BigInt(scale);\n } else if (typeof baseTime === 'number' && !isNaN(baseTime)) {\n seconds = baseTime / scale;\n }\n\n if (seconds < Number.MAX_SAFE_INTEGER) {\n seconds = Number(seconds);\n }\n\n if (seconds < acc) {\n acc = seconds;\n }\n\n return acc;\n }, Infinity);\n return typeof lowestTime === 'bigint' || isFinite(lowestTime) ? lowestTime : 0;\n };\n /**\n * Determine the composition start, in seconds, for an MP4\n * fragment.\n *\n * The composition start time of a fragment can be calculated using the base\n * media decode time, composition time offset, and timescale, as follows:\n *\n * compositionStartTime = (baseMediaDecodeTime + compositionTimeOffset) / timescale\n *\n * All of the aforementioned information is contained within a media fragment's\n * `traf` box, except for timescale info, which comes from the initialization\n * segment, so a track id (also contained within a `traf`) is also necessary to\n * associate it with a timescale\n *\n *\n * @param timescales {object} - a hash of track ids to timescale values.\n * @param fragment {Unit8Array} - the bytes of a media segment\n * @return {number} the composition start time for the fragment, in seconds\n **/\n\n\n compositionStartTime = function (timescales, fragment) {\n var trafBoxes = findBox$3(fragment, ['moof', 'traf']);\n var baseMediaDecodeTime = 0;\n var compositionTimeOffset = 0;\n var trackId;\n\n if (trafBoxes && trafBoxes.length) {\n // The spec states that track run samples contained within a `traf` box are contiguous, but\n // it does not explicitly state whether the `traf` boxes themselves are contiguous.\n // We will assume that they are, so we only need the first to calculate start time.\n var tfhd = findBox$3(trafBoxes[0], ['tfhd'])[0];\n var trun = findBox$3(trafBoxes[0], ['trun'])[0];\n var tfdt = findBox$3(trafBoxes[0], ['tfdt'])[0];\n\n if (tfhd) {\n var parsedTfhd = parseTfhd$1(tfhd);\n trackId = parsedTfhd.trackId;\n }\n\n if (tfdt) {\n var parsedTfdt = parseTfdt$2(tfdt);\n baseMediaDecodeTime = parsedTfdt.baseMediaDecodeTime;\n }\n\n if (trun) {\n var parsedTrun = parseTrun$1(trun);\n\n if (parsedTrun.samples && parsedTrun.samples.length) {\n compositionTimeOffset = parsedTrun.samples[0].compositionTimeOffset || 0;\n }\n }\n } // Get timescale for this specific track. Assume a 90kHz clock if no timescale was\n // specified.\n\n\n var timescale = timescales[trackId] || 90e3; // return the composition start time, in seconds\n\n if (typeof baseMediaDecodeTime === 'bigint') {\n compositionTimeOffset = window$2.BigInt(compositionTimeOffset);\n timescale = window$2.BigInt(timescale);\n }\n\n var result = (baseMediaDecodeTime + compositionTimeOffset) / timescale;\n\n if (typeof result === 'bigint' && result < Number.MAX_SAFE_INTEGER) {\n result = Number(result);\n }\n\n return result;\n };\n /**\n * Find the trackIds of the video tracks in this source.\n * Found by parsing the Handler Reference and Track Header Boxes:\n * moov > trak > mdia > hdlr\n * moov > trak > tkhd\n *\n * @param {Uint8Array} init - The bytes of the init segment for this source\n * @return {Number[]} A list of trackIds\n *\n * @see ISO-BMFF-12/2015, Section 8.4.3\n **/\n\n\n getVideoTrackIds = function (init) {\n var traks = findBox$3(init, ['moov', 'trak']);\n var videoTrackIds = [];\n traks.forEach(function (trak) {\n var hdlrs = findBox$3(trak, ['mdia', 'hdlr']);\n var tkhds = findBox$3(trak, ['tkhd']);\n hdlrs.forEach(function (hdlr, index) {\n var handlerType = parseType$1(hdlr.subarray(8, 12));\n var tkhd = tkhds[index];\n var view;\n var version;\n var trackId;\n\n if (handlerType === 'vide') {\n view = new DataView(tkhd.buffer, tkhd.byteOffset, tkhd.byteLength);\n version = view.getUint8(0);\n trackId = version === 0 ? view.getUint32(12) : view.getUint32(20);\n videoTrackIds.push(trackId);\n }\n });\n });\n return videoTrackIds;\n };\n\n getTimescaleFromMediaHeader$1 = function (mdhd) {\n // mdhd is a FullBox, meaning it will have its own version as the first byte\n var version = mdhd[0];\n var index = version === 0 ? 12 : 20;\n return toUnsigned(mdhd[index] << 24 | mdhd[index + 1] << 16 | mdhd[index + 2] << 8 | mdhd[index + 3]);\n };\n /**\n * Get all the video, audio, and hint tracks from a non fragmented\n * mp4 segment\n */\n\n\n getTracks = function (init) {\n var traks = findBox$3(init, ['moov', 'trak']);\n var tracks = [];\n traks.forEach(function (trak) {\n var track = {};\n var tkhd = findBox$3(trak, ['tkhd'])[0];\n var view, tkhdVersion; // id\n\n if (tkhd) {\n view = new DataView(tkhd.buffer, tkhd.byteOffset, tkhd.byteLength);\n tkhdVersion = view.getUint8(0);\n track.id = tkhdVersion === 0 ? view.getUint32(12) : view.getUint32(20);\n }\n\n var hdlr = findBox$3(trak, ['mdia', 'hdlr'])[0]; // type\n\n if (hdlr) {\n var type = parseType$1(hdlr.subarray(8, 12));\n\n if (type === 'vide') {\n track.type = 'video';\n } else if (type === 'soun') {\n track.type = 'audio';\n } else {\n track.type = type;\n }\n } // codec\n\n\n var stsd = findBox$3(trak, ['mdia', 'minf', 'stbl', 'stsd'])[0];\n\n if (stsd) {\n var sampleDescriptions = stsd.subarray(8); // gives the codec type string\n\n track.codec = parseType$1(sampleDescriptions.subarray(4, 8));\n var codecBox = findBox$3(sampleDescriptions, [track.codec])[0];\n var codecConfig, codecConfigType;\n\n if (codecBox) {\n // https://tools.ietf.org/html/rfc6381#section-3.3\n if (/^[asm]vc[1-9]$/i.test(track.codec)) {\n // we don't need anything but the \"config\" parameter of the\n // avc1 codecBox\n codecConfig = codecBox.subarray(78);\n codecConfigType = parseType$1(codecConfig.subarray(4, 8));\n\n if (codecConfigType === 'avcC' && codecConfig.length > 11) {\n track.codec += '.'; // left padded with zeroes for single digit hex\n // profile idc\n\n track.codec += toHexString(codecConfig[9]); // the byte containing the constraint_set flags\n\n track.codec += toHexString(codecConfig[10]); // level idc\n\n track.codec += toHexString(codecConfig[11]);\n } else {\n // TODO: show a warning that we couldn't parse the codec\n // and are using the default\n track.codec = 'avc1.4d400d';\n }\n } else if (/^mp4[a,v]$/i.test(track.codec)) {\n // we do not need anything but the streamDescriptor of the mp4a codecBox\n codecConfig = codecBox.subarray(28);\n codecConfigType = parseType$1(codecConfig.subarray(4, 8));\n\n if (codecConfigType === 'esds' && codecConfig.length > 20 && codecConfig[19] !== 0) {\n track.codec += '.' + toHexString(codecConfig[19]); // this value is only a single digit\n\n track.codec += '.' + toHexString(codecConfig[20] >>> 2 & 0x3f).replace(/^0/, '');\n } else {\n // TODO: show a warning that we couldn't parse the codec\n // and are using the default\n track.codec = 'mp4a.40.2';\n }\n } else {\n // flac, opus, etc\n track.codec = track.codec.toLowerCase();\n }\n }\n }\n\n var mdhd = findBox$3(trak, ['mdia', 'mdhd'])[0];\n\n if (mdhd) {\n track.timescale = getTimescaleFromMediaHeader$1(mdhd);\n }\n\n tracks.push(track);\n });\n return tracks;\n };\n /**\n * Returns an array of emsg ID3 data from the provided segmentData.\n * An offset can also be provided as the Latest Arrival Time to calculate \n * the Event Start Time of v0 EMSG boxes. \n * See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing\n * \n * @param {Uint8Array} segmentData the segment byte array.\n * @param {number} offset the segment start time or Latest Arrival Time, \n * @return {Object[]} an array of ID3 parsed from EMSG boxes\n */\n\n\n getEmsgID3 = function (segmentData, offset = 0) {\n var emsgBoxes = findBox$3(segmentData, ['emsg']);\n return emsgBoxes.map(data => {\n var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));\n var parsedId3Frames = parseId3Frames(parsedBox.message_data);\n return {\n cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),\n duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),\n frames: parsedId3Frames\n };\n });\n };\n\n var probe$2 = {\n // export mp4 inspector's findBox and parseType for backwards compatibility\n findBox: findBox$3,\n parseType: parseType$1,\n timescale: timescale,\n startTime: startTime,\n compositionStartTime: compositionStartTime,\n videoTrackIds: getVideoTrackIds,\n tracks: getTracks,\n getTimescaleFromMediaHeader: getTimescaleFromMediaHeader$1,\n getEmsgID3: getEmsgID3\n };\n const {\n parseTrun\n } = mp4Inspector;\n const {\n findBox: findBox$2\n } = probe$2;\n var window$1 = window_1;\n /**\n * Utility function for parsing data from mdat boxes.\n * @param {Array} segment the segment data to create mdat/traf pairs from.\n * @returns mdat and traf boxes paired up for easier parsing.\n */\n\n var getMdatTrafPairs$2 = function (segment) {\n var trafs = findBox$2(segment, ['moof', 'traf']);\n var mdats = findBox$2(segment, ['mdat']);\n var mdatTrafPairs = []; // Pair up each traf with a mdat as moofs and mdats are in pairs\n\n mdats.forEach(function (mdat, index) {\n var matchingTraf = trafs[index];\n mdatTrafPairs.push({\n mdat: mdat,\n traf: matchingTraf\n });\n });\n return mdatTrafPairs;\n };\n /**\n * Parses sample information out of Track Run Boxes and calculates\n * the absolute presentation and decode timestamps of each sample.\n *\n * @param {Array} truns - The Trun Run boxes to be parsed\n * @param {Number|BigInt} baseMediaDecodeTime - base media decode time from tfdt\n @see ISO-BMFF-12/2015, Section 8.8.12\n * @param {Object} tfhd - The parsed Track Fragment Header\n * @see inspect.parseTfhd\n * @return {Object[]} the parsed samples\n *\n * @see ISO-BMFF-12/2015, Section 8.8.8\n **/\n\n\n var parseSamples$2 = function (truns, baseMediaDecodeTime, tfhd) {\n var currentDts = baseMediaDecodeTime;\n var defaultSampleDuration = tfhd.defaultSampleDuration || 0;\n var defaultSampleSize = tfhd.defaultSampleSize || 0;\n var trackId = tfhd.trackId;\n var allSamples = [];\n truns.forEach(function (trun) {\n // Note: We currently do not parse the sample table as well\n // as the trun. It's possible some sources will require this.\n // moov > trak > mdia > minf > stbl\n var trackRun = parseTrun(trun);\n var samples = trackRun.samples;\n samples.forEach(function (sample) {\n if (sample.duration === undefined) {\n sample.duration = defaultSampleDuration;\n }\n\n if (sample.size === undefined) {\n sample.size = defaultSampleSize;\n }\n\n sample.trackId = trackId;\n sample.dts = currentDts;\n\n if (sample.compositionTimeOffset === undefined) {\n sample.compositionTimeOffset = 0;\n }\n\n if (typeof currentDts === 'bigint') {\n sample.pts = currentDts + window$1.BigInt(sample.compositionTimeOffset);\n currentDts += window$1.BigInt(sample.duration);\n } else {\n sample.pts = currentDts + sample.compositionTimeOffset;\n currentDts += sample.duration;\n }\n });\n allSamples = allSamples.concat(samples);\n });\n return allSamples;\n };\n\n var samples = {\n getMdatTrafPairs: getMdatTrafPairs$2,\n parseSamples: parseSamples$2\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Reads in-band CEA-708 captions out of FMP4 segments.\n * @see https://en.wikipedia.org/wiki/CEA-708\n */\n\n var discardEmulationPreventionBytes = captionPacketParser.discardEmulationPreventionBytes;\n var CaptionStream = captionStream.CaptionStream;\n var findBox$1 = findBox_1;\n var parseTfdt$1 = parseTfdt$3;\n var parseTfhd = parseTfhd$2;\n var {\n getMdatTrafPairs: getMdatTrafPairs$1,\n parseSamples: parseSamples$1\n } = samples;\n /**\n * Maps an offset in the mdat to a sample based on the the size of the samples.\n * Assumes that `parseSamples` has been called first.\n *\n * @param {Number} offset - The offset into the mdat\n * @param {Object[]} samples - An array of samples, parsed using `parseSamples`\n * @return {?Object} The matching sample, or null if no match was found.\n *\n * @see ISO-BMFF-12/2015, Section 8.8.8\n **/\n\n var mapToSample = function (offset, samples) {\n var approximateOffset = offset;\n\n for (var i = 0; i < samples.length; i++) {\n var sample = samples[i];\n\n if (approximateOffset < sample.size) {\n return sample;\n }\n\n approximateOffset -= sample.size;\n }\n\n return null;\n };\n /**\n * Finds SEI nal units contained in a Media Data Box.\n * Assumes that `parseSamples` has been called first.\n *\n * @param {Uint8Array} avcStream - The bytes of the mdat\n * @param {Object[]} samples - The samples parsed out by `parseSamples`\n * @param {Number} trackId - The trackId of this video track\n * @return {Object[]} seiNals - the parsed SEI NALUs found.\n * The contents of the seiNal should match what is expected by\n * CaptionStream.push (nalUnitType, size, data, escapedRBSP, pts, dts)\n *\n * @see ISO-BMFF-12/2015, Section 8.1.1\n * @see Rec. ITU-T H.264, 7.3.2.3.1\n **/\n\n\n var findSeiNals = function (avcStream, samples, trackId) {\n var avcView = new DataView(avcStream.buffer, avcStream.byteOffset, avcStream.byteLength),\n result = {\n logs: [],\n seiNals: []\n },\n seiNal,\n i,\n length,\n lastMatchedSample;\n\n for (i = 0; i + 4 < avcStream.length; i += length) {\n length = avcView.getUint32(i);\n i += 4; // Bail if this doesn't appear to be an H264 stream\n\n if (length <= 0) {\n continue;\n }\n\n switch (avcStream[i] & 0x1F) {\n case 0x06:\n var data = avcStream.subarray(i + 1, i + 1 + length);\n var matchingSample = mapToSample(i, samples);\n seiNal = {\n nalUnitType: 'sei_rbsp',\n size: length,\n data: data,\n escapedRBSP: discardEmulationPreventionBytes(data),\n trackId: trackId\n };\n\n if (matchingSample) {\n seiNal.pts = matchingSample.pts;\n seiNal.dts = matchingSample.dts;\n lastMatchedSample = matchingSample;\n } else if (lastMatchedSample) {\n // If a matching sample cannot be found, use the last\n // sample's values as they should be as close as possible\n seiNal.pts = lastMatchedSample.pts;\n seiNal.dts = lastMatchedSample.dts;\n } else {\n result.logs.push({\n level: 'warn',\n message: 'We\\'ve encountered a nal unit without data at ' + i + ' for trackId ' + trackId + '. See mux.js#223.'\n });\n break;\n }\n\n result.seiNals.push(seiNal);\n break;\n }\n }\n\n return result;\n };\n /**\n * Parses out caption nals from an FMP4 segment's video tracks.\n *\n * @param {Uint8Array} segment - The bytes of a single segment\n * @param {Number} videoTrackId - The trackId of a video track in the segment\n * @return {Object.} A mapping of video trackId to\n * a list of seiNals found in that track\n **/\n\n\n var parseCaptionNals = function (segment, videoTrackId) {\n var captionNals = {};\n var mdatTrafPairs = getMdatTrafPairs$1(segment);\n mdatTrafPairs.forEach(function (pair) {\n var mdat = pair.mdat;\n var traf = pair.traf;\n var tfhd = findBox$1(traf, ['tfhd']); // Exactly 1 tfhd per traf\n\n var headerInfo = parseTfhd(tfhd[0]);\n var trackId = headerInfo.trackId;\n var tfdt = findBox$1(traf, ['tfdt']); // Either 0 or 1 tfdt per traf\n\n var baseMediaDecodeTime = tfdt.length > 0 ? parseTfdt$1(tfdt[0]).baseMediaDecodeTime : 0;\n var truns = findBox$1(traf, ['trun']);\n var samples;\n var result; // Only parse video data for the chosen video track\n\n if (videoTrackId === trackId && truns.length > 0) {\n samples = parseSamples$1(truns, baseMediaDecodeTime, headerInfo);\n result = findSeiNals(mdat, samples, trackId);\n\n if (!captionNals[trackId]) {\n captionNals[trackId] = {\n seiNals: [],\n logs: []\n };\n }\n\n captionNals[trackId].seiNals = captionNals[trackId].seiNals.concat(result.seiNals);\n captionNals[trackId].logs = captionNals[trackId].logs.concat(result.logs);\n }\n });\n return captionNals;\n };\n /**\n * Parses out inband captions from an MP4 container and returns\n * caption objects that can be used by WebVTT and the TextTrack API.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/VTTCue\n * @see https://developer.mozilla.org/en-US/docs/Web/API/TextTrack\n * Assumes that `probe.getVideoTrackIds` and `probe.timescale` have been called first\n *\n * @param {Uint8Array} segment - The fmp4 segment containing embedded captions\n * @param {Number} trackId - The id of the video track to parse\n * @param {Number} timescale - The timescale for the video track from the init segment\n *\n * @return {?Object[]} parsedCaptions - A list of captions or null if no video tracks\n * @return {Number} parsedCaptions[].startTime - The time to show the caption in seconds\n * @return {Number} parsedCaptions[].endTime - The time to stop showing the caption in seconds\n * @return {Object[]} parsedCaptions[].content - A list of individual caption segments\n * @return {String} parsedCaptions[].content.text - The visible content of the caption segment\n * @return {Number} parsedCaptions[].content.line - The line height from 1-15 for positioning of the caption segment\n * @return {Number} parsedCaptions[].content.position - The column indent percentage for cue positioning from 10-80\n **/\n\n\n var parseEmbeddedCaptions = function (segment, trackId, timescale) {\n var captionNals; // the ISO-BMFF spec says that trackId can't be zero, but there's some broken content out there\n\n if (trackId === null) {\n return null;\n }\n\n captionNals = parseCaptionNals(segment, trackId);\n var trackNals = captionNals[trackId] || {};\n return {\n seiNals: trackNals.seiNals,\n logs: trackNals.logs,\n timescale: timescale\n };\n };\n /**\n * Converts SEI NALUs into captions that can be used by video.js\n **/\n\n\n var CaptionParser = function () {\n var isInitialized = false;\n var captionStream; // Stores segments seen before trackId and timescale are set\n\n var segmentCache; // Stores video track ID of the track being parsed\n\n var trackId; // Stores the timescale of the track being parsed\n\n var timescale; // Stores captions parsed so far\n\n var parsedCaptions; // Stores whether we are receiving partial data or not\n\n var parsingPartial;\n /**\n * A method to indicate whether a CaptionParser has been initalized\n * @returns {Boolean}\n **/\n\n this.isInitialized = function () {\n return isInitialized;\n };\n /**\n * Initializes the underlying CaptionStream, SEI NAL parsing\n * and management, and caption collection\n **/\n\n\n this.init = function (options) {\n captionStream = new CaptionStream();\n isInitialized = true;\n parsingPartial = options ? options.isPartial : false; // Collect dispatched captions\n\n captionStream.on('data', function (event) {\n // Convert to seconds in the source's timescale\n event.startTime = event.startPts / timescale;\n event.endTime = event.endPts / timescale;\n parsedCaptions.captions.push(event);\n parsedCaptions.captionStreams[event.stream] = true;\n });\n captionStream.on('log', function (log) {\n parsedCaptions.logs.push(log);\n });\n };\n /**\n * Determines if a new video track will be selected\n * or if the timescale changed\n * @return {Boolean}\n **/\n\n\n this.isNewInit = function (videoTrackIds, timescales) {\n if (videoTrackIds && videoTrackIds.length === 0 || timescales && typeof timescales === 'object' && Object.keys(timescales).length === 0) {\n return false;\n }\n\n return trackId !== videoTrackIds[0] || timescale !== timescales[trackId];\n };\n /**\n * Parses out SEI captions and interacts with underlying\n * CaptionStream to return dispatched captions\n *\n * @param {Uint8Array} segment - The fmp4 segment containing embedded captions\n * @param {Number[]} videoTrackIds - A list of video tracks found in the init segment\n * @param {Object.} timescales - The timescales found in the init segment\n * @see parseEmbeddedCaptions\n * @see m2ts/caption-stream.js\n **/\n\n\n this.parse = function (segment, videoTrackIds, timescales) {\n var parsedData;\n\n if (!this.isInitialized()) {\n return null; // This is not likely to be a video segment\n } else if (!videoTrackIds || !timescales) {\n return null;\n } else if (this.isNewInit(videoTrackIds, timescales)) {\n // Use the first video track only as there is no\n // mechanism to switch to other video tracks\n trackId = videoTrackIds[0];\n timescale = timescales[trackId]; // If an init segment has not been seen yet, hold onto segment\n // data until we have one.\n // the ISO-BMFF spec says that trackId can't be zero, but there's some broken content out there\n } else if (trackId === null || !timescale) {\n segmentCache.push(segment);\n return null;\n } // Now that a timescale and trackId is set, parse cached segments\n\n\n while (segmentCache.length > 0) {\n var cachedSegment = segmentCache.shift();\n this.parse(cachedSegment, videoTrackIds, timescales);\n }\n\n parsedData = parseEmbeddedCaptions(segment, trackId, timescale);\n\n if (parsedData && parsedData.logs) {\n parsedCaptions.logs = parsedCaptions.logs.concat(parsedData.logs);\n }\n\n if (parsedData === null || !parsedData.seiNals) {\n if (parsedCaptions.logs.length) {\n return {\n logs: parsedCaptions.logs,\n captions: [],\n captionStreams: []\n };\n }\n\n return null;\n }\n\n this.pushNals(parsedData.seiNals); // Force the parsed captions to be dispatched\n\n this.flushStream();\n return parsedCaptions;\n };\n /**\n * Pushes SEI NALUs onto CaptionStream\n * @param {Object[]} nals - A list of SEI nals parsed using `parseCaptionNals`\n * Assumes that `parseCaptionNals` has been called first\n * @see m2ts/caption-stream.js\n **/\n\n\n this.pushNals = function (nals) {\n if (!this.isInitialized() || !nals || nals.length === 0) {\n return null;\n }\n\n nals.forEach(function (nal) {\n captionStream.push(nal);\n });\n };\n /**\n * Flushes underlying CaptionStream to dispatch processed, displayable captions\n * @see m2ts/caption-stream.js\n **/\n\n\n this.flushStream = function () {\n if (!this.isInitialized()) {\n return null;\n }\n\n if (!parsingPartial) {\n captionStream.flush();\n } else {\n captionStream.partialFlush();\n }\n };\n /**\n * Reset caption buckets for new data\n **/\n\n\n this.clearParsedCaptions = function () {\n parsedCaptions.captions = [];\n parsedCaptions.captionStreams = {};\n parsedCaptions.logs = [];\n };\n /**\n * Resets underlying CaptionStream\n * @see m2ts/caption-stream.js\n **/\n\n\n this.resetCaptionStream = function () {\n if (!this.isInitialized()) {\n return null;\n }\n\n captionStream.reset();\n };\n /**\n * Convenience method to clear all captions flushed from the\n * CaptionStream and still being parsed\n * @see m2ts/caption-stream.js\n **/\n\n\n this.clearAllCaptions = function () {\n this.clearParsedCaptions();\n this.resetCaptionStream();\n };\n /**\n * Reset caption parser\n **/\n\n\n this.reset = function () {\n segmentCache = [];\n trackId = null;\n timescale = null;\n\n if (!parsedCaptions) {\n parsedCaptions = {\n captions: [],\n // CC1, CC2, CC3, CC4\n captionStreams: {},\n logs: []\n };\n } else {\n this.clearParsedCaptions();\n }\n\n this.resetCaptionStream();\n };\n\n this.reset();\n };\n\n var captionParser = CaptionParser;\n const {\n parseTfdt\n } = mp4Inspector;\n const findBox = findBox_1;\n const {\n getTimescaleFromMediaHeader\n } = probe$2;\n const {\n parseSamples,\n getMdatTrafPairs\n } = samples;\n /**\n * Module for parsing WebVTT text and styles from FMP4 segments.\n * Based on the ISO/IEC 14496-30.\n */\n\n const WebVttParser = function () {\n // default timescale to 90k\n let timescale = 90e3;\n /**\n * Parses the timescale from the init segment.\n * @param {Array} segment The initialization segment to parse the timescale from.\n */\n\n this.init = function (segment) {\n // We just need the timescale from the init segment.\n const mdhd = findBox(segment, ['moov', 'trak', 'mdia', 'mdhd'])[0];\n\n if (mdhd) {\n timescale = getTimescaleFromMediaHeader(mdhd);\n }\n };\n /**\n * Parses a WebVTT FMP4 segment.\n * @param {Array} segment The content segment to parse the WebVTT cues from.\n * @returns The WebVTT cue text, styling, and timing info as an array of cue objects.\n */\n\n\n this.parseSegment = function (segment) {\n const vttCues = [];\n const mdatTrafPairs = getMdatTrafPairs(segment);\n let baseMediaDecodeTime = 0;\n mdatTrafPairs.forEach(function (pair) {\n const mdatBox = pair.mdat;\n const trafBox = pair.traf; // zero or one.\n\n const tfdtBox = findBox(trafBox, ['tfdt'])[0]; // zero or one.\n\n const tfhdBox = findBox(trafBox, ['tfhd'])[0]; // zero or more.\n\n const trunBoxes = findBox(trafBox, ['trun']);\n\n if (tfdtBox) {\n const tfdt = parseTfdt(tfdtBox);\n baseMediaDecodeTime = tfdt.baseMediaDecodeTime;\n }\n\n if (trunBoxes.length && tfhdBox) {\n const samples = parseSamples(trunBoxes, baseMediaDecodeTime, tfhdBox);\n let mdatOffset = 0;\n samples.forEach(function (sample) {\n // decode utf8 payload\n const UTF_8 = 'utf-8';\n const textDecoder = new TextDecoder(UTF_8); // extract sample data from the mdat box.\n // WebVTT Sample format:\n // Exactly one VTTEmptyCueBox box\n // OR one or more VTTCueBox boxes.\n\n const sampleData = mdatBox.slice(mdatOffset, mdatOffset + sample.size); // single vtte box.\n\n const vtteBox = findBox(sampleData, ['vtte'])[0]; // empty box\n\n if (vtteBox) {\n mdatOffset += sample.size;\n return;\n } // TODO: Support 'vtta' boxes.\n // VTTAdditionalTextBoxes can be interleaved between VTTCueBoxes.\n\n\n const vttcBoxes = findBox(sampleData, ['vttc']);\n vttcBoxes.forEach(function (vttcBox) {\n // mandatory payload box.\n const paylBox = findBox(vttcBox, ['payl'])[0]; // optional settings box\n\n const sttgBox = findBox(vttcBox, ['sttg'])[0];\n const start = sample.pts / timescale;\n const end = (sample.pts + sample.duration) / timescale;\n let cueText, settings; // contains cue text.\n\n if (paylBox) {\n try {\n cueText = textDecoder.decode(paylBox);\n } catch (e) {\n console.error(e);\n }\n } // settings box contains styling.\n\n\n if (sttgBox) {\n try {\n settings = textDecoder.decode(sttgBox);\n } catch (e) {\n console.error(e);\n }\n }\n\n if (sample.duration && cueText) {\n vttCues.push({\n cueText,\n start,\n end,\n settings\n });\n }\n });\n mdatOffset += sample.size;\n });\n }\n });\n return vttCues;\n };\n };\n\n var webvttParser = WebVttParser;\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Utilities to detect basic properties and metadata about TS Segments.\n */\n\n var StreamTypes$1 = streamTypes;\n\n var parsePid = function (packet) {\n var pid = packet[1] & 0x1f;\n pid <<= 8;\n pid |= packet[2];\n return pid;\n };\n\n var parsePayloadUnitStartIndicator = function (packet) {\n return !!(packet[1] & 0x40);\n };\n\n var parseAdaptionField = function (packet) {\n var offset = 0; // if an adaption field is present, its length is specified by the\n // fifth byte of the TS packet header. The adaptation field is\n // used to add stuffing to PES packets that don't fill a complete\n // TS packet, and to specify some forms of timing and control data\n // that we do not currently use.\n\n if ((packet[3] & 0x30) >>> 4 > 0x01) {\n offset += packet[4] + 1;\n }\n\n return offset;\n };\n\n var parseType = function (packet, pmtPid) {\n var pid = parsePid(packet);\n\n if (pid === 0) {\n return 'pat';\n } else if (pid === pmtPid) {\n return 'pmt';\n } else if (pmtPid) {\n return 'pes';\n }\n\n return null;\n };\n\n var parsePat = function (packet) {\n var pusi = parsePayloadUnitStartIndicator(packet);\n var offset = 4 + parseAdaptionField(packet);\n\n if (pusi) {\n offset += packet[offset] + 1;\n }\n\n return (packet[offset + 10] & 0x1f) << 8 | packet[offset + 11];\n };\n\n var parsePmt = function (packet) {\n var programMapTable = {};\n var pusi = parsePayloadUnitStartIndicator(packet);\n var payloadOffset = 4 + parseAdaptionField(packet);\n\n if (pusi) {\n payloadOffset += packet[payloadOffset] + 1;\n } // PMTs can be sent ahead of the time when they should actually\n // take effect. We don't believe this should ever be the case\n // for HLS but we'll ignore \"forward\" PMT declarations if we see\n // them. Future PMT declarations have the current_next_indicator\n // set to zero.\n\n\n if (!(packet[payloadOffset + 5] & 0x01)) {\n return;\n }\n\n var sectionLength, tableEnd, programInfoLength; // the mapping table ends at the end of the current section\n\n sectionLength = (packet[payloadOffset + 1] & 0x0f) << 8 | packet[payloadOffset + 2];\n tableEnd = 3 + sectionLength - 4; // to determine where the table is, we have to figure out how\n // long the program info descriptors are\n\n programInfoLength = (packet[payloadOffset + 10] & 0x0f) << 8 | packet[payloadOffset + 11]; // advance the offset to the first entry in the mapping table\n\n var offset = 12 + programInfoLength;\n\n while (offset < tableEnd) {\n var i = payloadOffset + offset; // add an entry that maps the elementary_pid to the stream_type\n\n programMapTable[(packet[i + 1] & 0x1F) << 8 | packet[i + 2]] = packet[i]; // move to the next table entry\n // skip past the elementary stream descriptors, if present\n\n offset += ((packet[i + 3] & 0x0F) << 8 | packet[i + 4]) + 5;\n }\n\n return programMapTable;\n };\n\n var parsePesType = function (packet, programMapTable) {\n var pid = parsePid(packet);\n var type = programMapTable[pid];\n\n switch (type) {\n case StreamTypes$1.H264_STREAM_TYPE:\n return 'video';\n\n case StreamTypes$1.ADTS_STREAM_TYPE:\n return 'audio';\n\n case StreamTypes$1.METADATA_STREAM_TYPE:\n return 'timed-metadata';\n\n default:\n return null;\n }\n };\n\n var parsePesTime = function (packet) {\n var pusi = parsePayloadUnitStartIndicator(packet);\n\n if (!pusi) {\n return null;\n }\n\n var offset = 4 + parseAdaptionField(packet);\n\n if (offset >= packet.byteLength) {\n // From the H 222.0 MPEG-TS spec\n // \"For transport stream packets carrying PES packets, stuffing is needed when there\n // is insufficient PES packet data to completely fill the transport stream packet\n // payload bytes. Stuffing is accomplished by defining an adaptation field longer than\n // the sum of the lengths of the data elements in it, so that the payload bytes\n // remaining after the adaptation field exactly accommodates the available PES packet\n // data.\"\n //\n // If the offset is >= the length of the packet, then the packet contains no data\n // and instead is just adaption field stuffing bytes\n return null;\n }\n\n var pes = null;\n var ptsDtsFlags; // PES packets may be annotated with a PTS value, or a PTS value\n // and a DTS value. Determine what combination of values is\n // available to work with.\n\n ptsDtsFlags = packet[offset + 7]; // PTS and DTS are normally stored as a 33-bit number. Javascript\n // performs all bitwise operations on 32-bit integers but javascript\n // supports a much greater range (52-bits) of integer using standard\n // mathematical operations.\n // We construct a 31-bit value using bitwise operators over the 31\n // most significant bits and then multiply by 4 (equal to a left-shift\n // of 2) before we add the final 2 least significant bits of the\n // timestamp (equal to an OR.)\n\n if (ptsDtsFlags & 0xC0) {\n pes = {}; // the PTS and DTS are not written out directly. For information\n // on how they are encoded, see\n // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html\n\n pes.pts = (packet[offset + 9] & 0x0E) << 27 | (packet[offset + 10] & 0xFF) << 20 | (packet[offset + 11] & 0xFE) << 12 | (packet[offset + 12] & 0xFF) << 5 | (packet[offset + 13] & 0xFE) >>> 3;\n pes.pts *= 4; // Left shift by 2\n\n pes.pts += (packet[offset + 13] & 0x06) >>> 1; // OR by the two LSBs\n\n pes.dts = pes.pts;\n\n if (ptsDtsFlags & 0x40) {\n pes.dts = (packet[offset + 14] & 0x0E) << 27 | (packet[offset + 15] & 0xFF) << 20 | (packet[offset + 16] & 0xFE) << 12 | (packet[offset + 17] & 0xFF) << 5 | (packet[offset + 18] & 0xFE) >>> 3;\n pes.dts *= 4; // Left shift by 2\n\n pes.dts += (packet[offset + 18] & 0x06) >>> 1; // OR by the two LSBs\n }\n }\n\n return pes;\n };\n\n var parseNalUnitType = function (type) {\n switch (type) {\n case 0x05:\n return 'slice_layer_without_partitioning_rbsp_idr';\n\n case 0x06:\n return 'sei_rbsp';\n\n case 0x07:\n return 'seq_parameter_set_rbsp';\n\n case 0x08:\n return 'pic_parameter_set_rbsp';\n\n case 0x09:\n return 'access_unit_delimiter_rbsp';\n\n default:\n return null;\n }\n };\n\n var videoPacketContainsKeyFrame = function (packet) {\n var offset = 4 + parseAdaptionField(packet);\n var frameBuffer = packet.subarray(offset);\n var frameI = 0;\n var frameSyncPoint = 0;\n var foundKeyFrame = false;\n var nalType; // advance the sync point to a NAL start, if necessary\n\n for (; frameSyncPoint < frameBuffer.byteLength - 3; frameSyncPoint++) {\n if (frameBuffer[frameSyncPoint + 2] === 1) {\n // the sync point is properly aligned\n frameI = frameSyncPoint + 5;\n break;\n }\n }\n\n while (frameI < frameBuffer.byteLength) {\n // look at the current byte to determine if we've hit the end of\n // a NAL unit boundary\n switch (frameBuffer[frameI]) {\n case 0:\n // skip past non-sync sequences\n if (frameBuffer[frameI - 1] !== 0) {\n frameI += 2;\n break;\n } else if (frameBuffer[frameI - 2] !== 0) {\n frameI++;\n break;\n }\n\n if (frameSyncPoint + 3 !== frameI - 2) {\n nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);\n\n if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {\n foundKeyFrame = true;\n }\n } // drop trailing zeroes\n\n\n do {\n frameI++;\n } while (frameBuffer[frameI] !== 1 && frameI < frameBuffer.length);\n\n frameSyncPoint = frameI - 2;\n frameI += 3;\n break;\n\n case 1:\n // skip past non-sync sequences\n if (frameBuffer[frameI - 1] !== 0 || frameBuffer[frameI - 2] !== 0) {\n frameI += 3;\n break;\n }\n\n nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);\n\n if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {\n foundKeyFrame = true;\n }\n\n frameSyncPoint = frameI - 2;\n frameI += 3;\n break;\n\n default:\n // the current byte isn't a one or zero, so it cannot be part\n // of a sync sequence\n frameI += 3;\n break;\n }\n }\n\n frameBuffer = frameBuffer.subarray(frameSyncPoint);\n frameI -= frameSyncPoint;\n frameSyncPoint = 0; // parse the final nal\n\n if (frameBuffer && frameBuffer.byteLength > 3) {\n nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);\n\n if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {\n foundKeyFrame = true;\n }\n }\n\n return foundKeyFrame;\n };\n\n var probe$1 = {\n parseType: parseType,\n parsePat: parsePat,\n parsePmt: parsePmt,\n parsePayloadUnitStartIndicator: parsePayloadUnitStartIndicator,\n parsePesType: parsePesType,\n parsePesTime: parsePesTime,\n videoPacketContainsKeyFrame: videoPacketContainsKeyFrame\n };\n /**\n * mux.js\n *\n * Copyright (c) Brightcove\n * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE\n *\n * Parse mpeg2 transport stream packets to extract basic timing information\n */\n\n var StreamTypes = streamTypes;\n var handleRollover = timestampRolloverStream.handleRollover;\n var probe = {};\n probe.ts = probe$1;\n probe.aac = utils;\n var ONE_SECOND_IN_TS = clock$2.ONE_SECOND_IN_TS;\n var MP2T_PACKET_LENGTH = 188,\n // bytes\n SYNC_BYTE = 0x47;\n /**\n * walks through segment data looking for pat and pmt packets to parse out\n * program map table information\n */\n\n var parsePsi_ = function (bytes, pmt) {\n var startIndex = 0,\n endIndex = MP2T_PACKET_LENGTH,\n packet,\n type;\n\n while (endIndex < bytes.byteLength) {\n // Look for a pair of start and end sync bytes in the data..\n if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {\n // We found a packet\n packet = bytes.subarray(startIndex, endIndex);\n type = probe.ts.parseType(packet, pmt.pid);\n\n switch (type) {\n case 'pat':\n pmt.pid = probe.ts.parsePat(packet);\n break;\n\n case 'pmt':\n var table = probe.ts.parsePmt(packet);\n pmt.table = pmt.table || {};\n Object.keys(table).forEach(function (key) {\n pmt.table[key] = table[key];\n });\n break;\n }\n\n startIndex += MP2T_PACKET_LENGTH;\n endIndex += MP2T_PACKET_LENGTH;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex++;\n endIndex++;\n }\n };\n /**\n * walks through the segment data from the start and end to get timing information\n * for the first and last audio pes packets\n */\n\n\n var parseAudioPes_ = function (bytes, pmt, result) {\n var startIndex = 0,\n endIndex = MP2T_PACKET_LENGTH,\n packet,\n type,\n pesType,\n pusi,\n parsed;\n var endLoop = false; // Start walking from start of segment to get first audio packet\n\n while (endIndex <= bytes.byteLength) {\n // Look for a pair of start and end sync bytes in the data..\n if (bytes[startIndex] === SYNC_BYTE && (bytes[endIndex] === SYNC_BYTE || endIndex === bytes.byteLength)) {\n // We found a packet\n packet = bytes.subarray(startIndex, endIndex);\n type = probe.ts.parseType(packet, pmt.pid);\n\n switch (type) {\n case 'pes':\n pesType = probe.ts.parsePesType(packet, pmt.table);\n pusi = probe.ts.parsePayloadUnitStartIndicator(packet);\n\n if (pesType === 'audio' && pusi) {\n parsed = probe.ts.parsePesTime(packet);\n\n if (parsed) {\n parsed.type = 'audio';\n result.audio.push(parsed);\n endLoop = true;\n }\n }\n\n break;\n }\n\n if (endLoop) {\n break;\n }\n\n startIndex += MP2T_PACKET_LENGTH;\n endIndex += MP2T_PACKET_LENGTH;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex++;\n endIndex++;\n } // Start walking from end of segment to get last audio packet\n\n\n endIndex = bytes.byteLength;\n startIndex = endIndex - MP2T_PACKET_LENGTH;\n endLoop = false;\n\n while (startIndex >= 0) {\n // Look for a pair of start and end sync bytes in the data..\n if (bytes[startIndex] === SYNC_BYTE && (bytes[endIndex] === SYNC_BYTE || endIndex === bytes.byteLength)) {\n // We found a packet\n packet = bytes.subarray(startIndex, endIndex);\n type = probe.ts.parseType(packet, pmt.pid);\n\n switch (type) {\n case 'pes':\n pesType = probe.ts.parsePesType(packet, pmt.table);\n pusi = probe.ts.parsePayloadUnitStartIndicator(packet);\n\n if (pesType === 'audio' && pusi) {\n parsed = probe.ts.parsePesTime(packet);\n\n if (parsed) {\n parsed.type = 'audio';\n result.audio.push(parsed);\n endLoop = true;\n }\n }\n\n break;\n }\n\n if (endLoop) {\n break;\n }\n\n startIndex -= MP2T_PACKET_LENGTH;\n endIndex -= MP2T_PACKET_LENGTH;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex--;\n endIndex--;\n }\n };\n /**\n * walks through the segment data from the start and end to get timing information\n * for the first and last video pes packets as well as timing information for the first\n * key frame.\n */\n\n\n var parseVideoPes_ = function (bytes, pmt, result) {\n var startIndex = 0,\n endIndex = MP2T_PACKET_LENGTH,\n packet,\n type,\n pesType,\n pusi,\n parsed,\n frame,\n i,\n pes;\n var endLoop = false;\n var currentFrame = {\n data: [],\n size: 0\n }; // Start walking from start of segment to get first video packet\n\n while (endIndex < bytes.byteLength) {\n // Look for a pair of start and end sync bytes in the data..\n if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {\n // We found a packet\n packet = bytes.subarray(startIndex, endIndex);\n type = probe.ts.parseType(packet, pmt.pid);\n\n switch (type) {\n case 'pes':\n pesType = probe.ts.parsePesType(packet, pmt.table);\n pusi = probe.ts.parsePayloadUnitStartIndicator(packet);\n\n if (pesType === 'video') {\n if (pusi && !endLoop) {\n parsed = probe.ts.parsePesTime(packet);\n\n if (parsed) {\n parsed.type = 'video';\n result.video.push(parsed);\n endLoop = true;\n }\n }\n\n if (!result.firstKeyFrame) {\n if (pusi) {\n if (currentFrame.size !== 0) {\n frame = new Uint8Array(currentFrame.size);\n i = 0;\n\n while (currentFrame.data.length) {\n pes = currentFrame.data.shift();\n frame.set(pes, i);\n i += pes.byteLength;\n }\n\n if (probe.ts.videoPacketContainsKeyFrame(frame)) {\n var firstKeyFrame = probe.ts.parsePesTime(frame); // PTS/DTS may not be available. Simply *not* setting\n // the keyframe seems to work fine with HLS playback\n // and definitely preferable to a crash with TypeError...\n\n if (firstKeyFrame) {\n result.firstKeyFrame = firstKeyFrame;\n result.firstKeyFrame.type = 'video';\n } else {\n // eslint-disable-next-line\n console.warn('Failed to extract PTS/DTS from PES at first keyframe. ' + 'This could be an unusual TS segment, or else mux.js did not ' + 'parse your TS segment correctly. If you know your TS ' + 'segments do contain PTS/DTS on keyframes please file a bug ' + 'report! You can try ffprobe to double check for yourself.');\n }\n }\n\n currentFrame.size = 0;\n }\n }\n\n currentFrame.data.push(packet);\n currentFrame.size += packet.byteLength;\n }\n }\n\n break;\n }\n\n if (endLoop && result.firstKeyFrame) {\n break;\n }\n\n startIndex += MP2T_PACKET_LENGTH;\n endIndex += MP2T_PACKET_LENGTH;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex++;\n endIndex++;\n } // Start walking from end of segment to get last video packet\n\n\n endIndex = bytes.byteLength;\n startIndex = endIndex - MP2T_PACKET_LENGTH;\n endLoop = false;\n\n while (startIndex >= 0) {\n // Look for a pair of start and end sync bytes in the data..\n if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {\n // We found a packet\n packet = bytes.subarray(startIndex, endIndex);\n type = probe.ts.parseType(packet, pmt.pid);\n\n switch (type) {\n case 'pes':\n pesType = probe.ts.parsePesType(packet, pmt.table);\n pusi = probe.ts.parsePayloadUnitStartIndicator(packet);\n\n if (pesType === 'video' && pusi) {\n parsed = probe.ts.parsePesTime(packet);\n\n if (parsed) {\n parsed.type = 'video';\n result.video.push(parsed);\n endLoop = true;\n }\n }\n\n break;\n }\n\n if (endLoop) {\n break;\n }\n\n startIndex -= MP2T_PACKET_LENGTH;\n endIndex -= MP2T_PACKET_LENGTH;\n continue;\n } // If we get here, we have somehow become de-synchronized and we need to step\n // forward one byte at a time until we find a pair of sync bytes that denote\n // a packet\n\n\n startIndex--;\n endIndex--;\n }\n };\n /**\n * Adjusts the timestamp information for the segment to account for\n * rollover and convert to seconds based on pes packet timescale (90khz clock)\n */\n\n\n var adjustTimestamp_ = function (segmentInfo, baseTimestamp) {\n if (segmentInfo.audio && segmentInfo.audio.length) {\n var audioBaseTimestamp = baseTimestamp;\n\n if (typeof audioBaseTimestamp === 'undefined' || isNaN(audioBaseTimestamp)) {\n audioBaseTimestamp = segmentInfo.audio[0].dts;\n }\n\n segmentInfo.audio.forEach(function (info) {\n info.dts = handleRollover(info.dts, audioBaseTimestamp);\n info.pts = handleRollover(info.pts, audioBaseTimestamp); // time in seconds\n\n info.dtsTime = info.dts / ONE_SECOND_IN_TS;\n info.ptsTime = info.pts / ONE_SECOND_IN_TS;\n });\n }\n\n if (segmentInfo.video && segmentInfo.video.length) {\n var videoBaseTimestamp = baseTimestamp;\n\n if (typeof videoBaseTimestamp === 'undefined' || isNaN(videoBaseTimestamp)) {\n videoBaseTimestamp = segmentInfo.video[0].dts;\n }\n\n segmentInfo.video.forEach(function (info) {\n info.dts = handleRollover(info.dts, videoBaseTimestamp);\n info.pts = handleRollover(info.pts, videoBaseTimestamp); // time in seconds\n\n info.dtsTime = info.dts / ONE_SECOND_IN_TS;\n info.ptsTime = info.pts / ONE_SECOND_IN_TS;\n });\n\n if (segmentInfo.firstKeyFrame) {\n var frame = segmentInfo.firstKeyFrame;\n frame.dts = handleRollover(frame.dts, videoBaseTimestamp);\n frame.pts = handleRollover(frame.pts, videoBaseTimestamp); // time in seconds\n\n frame.dtsTime = frame.dts / ONE_SECOND_IN_TS;\n frame.ptsTime = frame.pts / ONE_SECOND_IN_TS;\n }\n }\n };\n /**\n * inspects the aac data stream for start and end time information\n */\n\n\n var inspectAac_ = function (bytes) {\n var endLoop = false,\n audioCount = 0,\n sampleRate = null,\n timestamp = null,\n frameSize = 0,\n byteIndex = 0,\n packet;\n\n while (bytes.length - byteIndex >= 3) {\n var type = probe.aac.parseType(bytes, byteIndex);\n\n switch (type) {\n case 'timed-metadata':\n // Exit early because we don't have enough to parse\n // the ID3 tag header\n if (bytes.length - byteIndex < 10) {\n endLoop = true;\n break;\n }\n\n frameSize = probe.aac.parseId3TagSize(bytes, byteIndex); // Exit early if we don't have enough in the buffer\n // to emit a full packet\n\n if (frameSize > bytes.length) {\n endLoop = true;\n break;\n }\n\n if (timestamp === null) {\n packet = bytes.subarray(byteIndex, byteIndex + frameSize);\n timestamp = probe.aac.parseAacTimestamp(packet);\n }\n\n byteIndex += frameSize;\n break;\n\n case 'audio':\n // Exit early because we don't have enough to parse\n // the ADTS frame header\n if (bytes.length - byteIndex < 7) {\n endLoop = true;\n break;\n }\n\n frameSize = probe.aac.parseAdtsSize(bytes, byteIndex); // Exit early if we don't have enough in the buffer\n // to emit a full packet\n\n if (frameSize > bytes.length) {\n endLoop = true;\n break;\n }\n\n if (sampleRate === null) {\n packet = bytes.subarray(byteIndex, byteIndex + frameSize);\n sampleRate = probe.aac.parseSampleRate(packet);\n }\n\n audioCount++;\n byteIndex += frameSize;\n break;\n\n default:\n byteIndex++;\n break;\n }\n\n if (endLoop) {\n return null;\n }\n }\n\n if (sampleRate === null || timestamp === null) {\n return null;\n }\n\n var audioTimescale = ONE_SECOND_IN_TS / sampleRate;\n var result = {\n audio: [{\n type: 'audio',\n dts: timestamp,\n pts: timestamp\n }, {\n type: 'audio',\n dts: timestamp + audioCount * 1024 * audioTimescale,\n pts: timestamp + audioCount * 1024 * audioTimescale\n }]\n };\n return result;\n };\n /**\n * inspects the transport stream segment data for start and end time information\n * of the audio and video tracks (when present) as well as the first key frame's\n * start time.\n */\n\n\n var inspectTs_ = function (bytes) {\n var pmt = {\n pid: null,\n table: null\n };\n var result = {};\n parsePsi_(bytes, pmt);\n\n for (var pid in pmt.table) {\n if (pmt.table.hasOwnProperty(pid)) {\n var type = pmt.table[pid];\n\n switch (type) {\n case StreamTypes.H264_STREAM_TYPE:\n result.video = [];\n parseVideoPes_(bytes, pmt, result);\n\n if (result.video.length === 0) {\n delete result.video;\n }\n\n break;\n\n case StreamTypes.ADTS_STREAM_TYPE:\n result.audio = [];\n parseAudioPes_(bytes, pmt, result);\n\n if (result.audio.length === 0) {\n delete result.audio;\n }\n\n break;\n }\n }\n }\n\n return result;\n };\n /**\n * Inspects segment byte data and returns an object with start and end timing information\n *\n * @param {Uint8Array} bytes The segment byte data\n * @param {Number} baseTimestamp Relative reference timestamp used when adjusting frame\n * timestamps for rollover. This value must be in 90khz clock.\n * @return {Object} Object containing start and end frame timing info of segment.\n */\n\n\n var inspect = function (bytes, baseTimestamp) {\n var isAacData = probe.aac.isLikelyAacData(bytes);\n var result;\n\n if (isAacData) {\n result = inspectAac_(bytes);\n } else {\n result = inspectTs_(bytes);\n }\n\n if (!result || !result.audio && !result.video) {\n return null;\n }\n\n adjustTimestamp_(result, baseTimestamp);\n return result;\n };\n\n var tsInspector = {\n inspect: inspect,\n parseAudioPes_: parseAudioPes_\n };\n /* global self */\n\n /**\n * Re-emits transmuxer events by converting them into messages to the\n * world outside the worker.\n *\n * @param {Object} transmuxer the transmuxer to wire events on\n * @private\n */\n\n const wireTransmuxerEvents = function (self, transmuxer) {\n transmuxer.on('data', function (segment) {\n // transfer ownership of the underlying ArrayBuffer\n // instead of doing a copy to save memory\n // ArrayBuffers are transferable but generic TypedArrays are not\n // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)\n const initArray = segment.initSegment;\n segment.initSegment = {\n data: initArray.buffer,\n byteOffset: initArray.byteOffset,\n byteLength: initArray.byteLength\n };\n const typedArray = segment.data;\n segment.data = typedArray.buffer;\n self.postMessage({\n action: 'data',\n segment,\n byteOffset: typedArray.byteOffset,\n byteLength: typedArray.byteLength\n }, [segment.data]);\n });\n transmuxer.on('done', function (data) {\n self.postMessage({\n action: 'done'\n });\n });\n transmuxer.on('gopInfo', function (gopInfo) {\n self.postMessage({\n action: 'gopInfo',\n gopInfo\n });\n });\n transmuxer.on('videoSegmentTimingInfo', function (timingInfo) {\n const videoSegmentTimingInfo = {\n start: {\n decode: clock$2.videoTsToSeconds(timingInfo.start.dts),\n presentation: clock$2.videoTsToSeconds(timingInfo.start.pts)\n },\n end: {\n decode: clock$2.videoTsToSeconds(timingInfo.end.dts),\n presentation: clock$2.videoTsToSeconds(timingInfo.end.pts)\n },\n baseMediaDecodeTime: clock$2.videoTsToSeconds(timingInfo.baseMediaDecodeTime)\n };\n\n if (timingInfo.prependedContentDuration) {\n videoSegmentTimingInfo.prependedContentDuration = clock$2.videoTsToSeconds(timingInfo.prependedContentDuration);\n }\n\n self.postMessage({\n action: 'videoSegmentTimingInfo',\n videoSegmentTimingInfo\n });\n });\n transmuxer.on('audioSegmentTimingInfo', function (timingInfo) {\n // Note that all times for [audio/video]SegmentTimingInfo events are in video clock\n const audioSegmentTimingInfo = {\n start: {\n decode: clock$2.videoTsToSeconds(timingInfo.start.dts),\n presentation: clock$2.videoTsToSeconds(timingInfo.start.pts)\n },\n end: {\n decode: clock$2.videoTsToSeconds(timingInfo.end.dts),\n presentation: clock$2.videoTsToSeconds(timingInfo.end.pts)\n },\n baseMediaDecodeTime: clock$2.videoTsToSeconds(timingInfo.baseMediaDecodeTime)\n };\n\n if (timingInfo.prependedContentDuration) {\n audioSegmentTimingInfo.prependedContentDuration = clock$2.videoTsToSeconds(timingInfo.prependedContentDuration);\n }\n\n self.postMessage({\n action: 'audioSegmentTimingInfo',\n audioSegmentTimingInfo\n });\n });\n transmuxer.on('id3Frame', function (id3Frame) {\n self.postMessage({\n action: 'id3Frame',\n id3Frame\n });\n });\n transmuxer.on('caption', function (caption) {\n self.postMessage({\n action: 'caption',\n caption\n });\n });\n transmuxer.on('trackinfo', function (trackInfo) {\n self.postMessage({\n action: 'trackinfo',\n trackInfo\n });\n });\n transmuxer.on('audioTimingInfo', function (audioTimingInfo) {\n // convert to video TS since we prioritize video time over audio\n self.postMessage({\n action: 'audioTimingInfo',\n audioTimingInfo: {\n start: clock$2.videoTsToSeconds(audioTimingInfo.start),\n end: clock$2.videoTsToSeconds(audioTimingInfo.end)\n }\n });\n });\n transmuxer.on('videoTimingInfo', function (videoTimingInfo) {\n self.postMessage({\n action: 'videoTimingInfo',\n videoTimingInfo: {\n start: clock$2.videoTsToSeconds(videoTimingInfo.start),\n end: clock$2.videoTsToSeconds(videoTimingInfo.end)\n }\n });\n });\n transmuxer.on('log', function (log) {\n self.postMessage({\n action: 'log',\n log\n });\n });\n };\n /**\n * All incoming messages route through this hash. If no function exists\n * to handle an incoming message, then we ignore the message.\n *\n * @class MessageHandlers\n * @param {Object} options the options to initialize with\n */\n\n\n class MessageHandlers {\n constructor(self, options) {\n this.options = options || {};\n this.self = self;\n this.init();\n }\n /**\n * initialize our web worker and wire all the events.\n */\n\n\n init() {\n if (this.transmuxer) {\n this.transmuxer.dispose();\n }\n\n this.transmuxer = new transmuxer.Transmuxer(this.options);\n wireTransmuxerEvents(this.self, this.transmuxer);\n }\n\n pushMp4Captions(data) {\n if (!this.captionParser) {\n this.captionParser = new captionParser();\n this.captionParser.init();\n }\n\n const segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);\n const parsed = this.captionParser.parse(segment, data.trackIds, data.timescales);\n this.self.postMessage({\n action: 'mp4Captions',\n captions: parsed && parsed.captions || [],\n logs: parsed && parsed.logs || [],\n data: segment.buffer\n }, [segment.buffer]);\n }\n /**\n * Initializes the WebVttParser and passes the init segment.\n *\n * @param {Uint8Array} data mp4 boxed WebVTT init segment data\n */\n\n\n initMp4WebVttParser(data) {\n if (!this.webVttParser) {\n this.webVttParser = new webvttParser();\n }\n\n const segment = new Uint8Array(data.data, data.byteOffset, data.byteLength); // Set the timescale for the parser.\n // This can be called repeatedly in order to set and re-set the timescale.\n\n this.webVttParser.init(segment);\n }\n /**\n * Parse an mp4 encapsulated WebVTT segment and return an array of cues.\n *\n * @param {Uint8Array} data a text/webvtt segment\n * @return {Object[]} an array of parsed cue objects\n */\n\n\n getMp4WebVttText(data) {\n if (!this.webVttParser) {\n // timescale might not be set yet if the parser is created before an init segment is passed.\n // default timescale is 90k.\n this.webVttParser = new webvttParser();\n }\n\n const segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);\n const parsed = this.webVttParser.parseSegment(segment);\n this.self.postMessage({\n action: 'getMp4WebVttText',\n mp4VttCues: parsed || [],\n data: segment.buffer\n }, [segment.buffer]);\n }\n\n probeMp4StartTime({\n timescales,\n data\n }) {\n const startTime = probe$2.startTime(timescales, data);\n this.self.postMessage({\n action: 'probeMp4StartTime',\n startTime,\n data\n }, [data.buffer]);\n }\n\n probeMp4Tracks({\n data\n }) {\n const tracks = probe$2.tracks(data);\n this.self.postMessage({\n action: 'probeMp4Tracks',\n tracks,\n data\n }, [data.buffer]);\n }\n /**\n * Probes an mp4 segment for EMSG boxes containing ID3 data.\n * https://aomediacodec.github.io/id3-emsg/\n *\n * @param {Uint8Array} data segment data\n * @param {number} offset segment start time\n * @return {Object[]} an array of ID3 frames\n */\n\n\n probeEmsgID3({\n data,\n offset\n }) {\n const id3Frames = probe$2.getEmsgID3(data, offset);\n this.self.postMessage({\n action: 'probeEmsgID3',\n id3Frames,\n emsgData: data\n }, [data.buffer]);\n }\n /**\n * Probe an mpeg2-ts segment to determine the start time of the segment in it's\n * internal \"media time,\" as well as whether it contains video and/or audio.\n *\n * @private\n * @param {Uint8Array} bytes - segment bytes\n * @param {number} baseStartTime\n * Relative reference timestamp used when adjusting frame timestamps for rollover.\n * This value should be in seconds, as it's converted to a 90khz clock within the\n * function body.\n * @return {Object} The start time of the current segment in \"media time\" as well as\n * whether it contains video and/or audio\n */\n\n\n probeTs({\n data,\n baseStartTime\n }) {\n const tsStartTime = typeof baseStartTime === 'number' && !isNaN(baseStartTime) ? baseStartTime * clock$2.ONE_SECOND_IN_TS : void 0;\n const timeInfo = tsInspector.inspect(data, tsStartTime);\n let result = null;\n\n if (timeInfo) {\n result = {\n // each type's time info comes back as an array of 2 times, start and end\n hasVideo: timeInfo.video && timeInfo.video.length === 2 || false,\n hasAudio: timeInfo.audio && timeInfo.audio.length === 2 || false\n };\n\n if (result.hasVideo) {\n result.videoStart = timeInfo.video[0].ptsTime;\n }\n\n if (result.hasAudio) {\n result.audioStart = timeInfo.audio[0].ptsTime;\n }\n }\n\n this.self.postMessage({\n action: 'probeTs',\n result,\n data\n }, [data.buffer]);\n }\n\n clearAllMp4Captions() {\n if (this.captionParser) {\n this.captionParser.clearAllCaptions();\n }\n }\n\n clearParsedMp4Captions() {\n if (this.captionParser) {\n this.captionParser.clearParsedCaptions();\n }\n }\n /**\n * Adds data (a ts segment) to the start of the transmuxer pipeline for\n * processing.\n *\n * @param {ArrayBuffer} data data to push into the muxer\n */\n\n\n push(data) {\n // Cast array buffer to correct type for transmuxer\n const segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);\n this.transmuxer.push(segment);\n }\n /**\n * Recreate the transmuxer so that the next segment added via `push`\n * start with a fresh transmuxer.\n */\n\n\n reset() {\n this.transmuxer.reset();\n }\n /**\n * Set the value that will be used as the `baseMediaDecodeTime` time for the\n * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime`\n * set relative to the first based on the PTS values.\n *\n * @param {Object} data used to set the timestamp offset in the muxer\n */\n\n\n setTimestampOffset(data) {\n const timestampOffset = data.timestampOffset || 0;\n this.transmuxer.setBaseMediaDecodeTime(Math.round(clock$2.secondsToVideoTs(timestampOffset)));\n }\n\n setAudioAppendStart(data) {\n this.transmuxer.setAudioAppendStart(Math.ceil(clock$2.secondsToVideoTs(data.appendStart)));\n }\n\n setRemux(data) {\n this.transmuxer.setRemux(data.remux);\n }\n /**\n * Forces the pipeline to finish processing the last segment and emit it's\n * results.\n *\n * @param {Object} data event data, not really used\n */\n\n\n flush(data) {\n this.transmuxer.flush(); // transmuxed done action is fired after both audio/video pipelines are flushed\n\n self.postMessage({\n action: 'done',\n type: 'transmuxed'\n });\n }\n\n endTimeline() {\n this.transmuxer.endTimeline(); // transmuxed endedtimeline action is fired after both audio/video pipelines end their\n // timelines\n\n self.postMessage({\n action: 'endedtimeline',\n type: 'transmuxed'\n });\n }\n\n alignGopsWith(data) {\n this.transmuxer.alignGopsWith(data.gopsToAlignWith.slice());\n }\n\n }\n /**\n * Our web worker interface so that things can talk to mux.js\n * that will be running in a web worker. the scope is passed to this by\n * webworkify.\n *\n * @param {Object} self the scope for the web worker\n */\n\n\n self.onmessage = function (event) {\n if (event.data.action === 'init' && event.data.options) {\n this.messageHandlers = new MessageHandlers(self, event.data.options);\n return;\n }\n\n if (!this.messageHandlers) {\n this.messageHandlers = new MessageHandlers(self);\n }\n\n if (event.data && event.data.action && event.data.action !== 'init') {\n if (this.messageHandlers[event.data.action]) {\n this.messageHandlers[event.data.action](event.data);\n }\n }\n };\n}));\nvar TransmuxWorker = factory(workerCode$1);\n/* rollup-plugin-worker-factory end for worker!/home/runner/work/http-streaming/http-streaming/src/transmuxer-worker.js */\n\nconst handleData_ = (event, transmuxedData, callback) => {\n const {\n type,\n initSegment,\n captions,\n captionStreams,\n metadata,\n videoFrameDtsTime,\n videoFramePtsTime\n } = event.data.segment;\n transmuxedData.buffer.push({\n captions,\n captionStreams,\n metadata\n });\n const boxes = event.data.segment.boxes || {\n data: event.data.segment.data\n };\n const result = {\n type,\n // cast ArrayBuffer to TypedArray\n data: new Uint8Array(boxes.data, boxes.data.byteOffset, boxes.data.byteLength),\n initSegment: new Uint8Array(initSegment.data, initSegment.byteOffset, initSegment.byteLength)\n };\n\n if (typeof videoFrameDtsTime !== 'undefined') {\n result.videoFrameDtsTime = videoFrameDtsTime;\n }\n\n if (typeof videoFramePtsTime !== 'undefined') {\n result.videoFramePtsTime = videoFramePtsTime;\n }\n\n callback(result);\n};\nconst handleDone_ = ({\n transmuxedData,\n callback\n}) => {\n // Previously we only returned data on data events,\n // not on done events. Clear out the buffer to keep that consistent.\n transmuxedData.buffer = []; // all buffers should have been flushed from the muxer, so start processing anything we\n // have received\n\n callback(transmuxedData);\n};\nconst handleGopInfo_ = (event, transmuxedData) => {\n transmuxedData.gopInfo = event.data.gopInfo;\n};\nconst processTransmux = options => {\n const {\n transmuxer,\n bytes,\n audioAppendStart,\n gopsToAlignWith,\n remux,\n onData,\n onTrackInfo,\n onAudioTimingInfo,\n onVideoTimingInfo,\n onVideoSegmentTimingInfo,\n onAudioSegmentTimingInfo,\n onId3,\n onCaptions,\n onDone,\n onEndedTimeline,\n onTransmuxerLog,\n isEndOfTimeline,\n segment,\n triggerSegmentEventFn\n } = options;\n const transmuxedData = {\n buffer: []\n };\n let waitForEndedTimelineEvent = isEndOfTimeline;\n\n const handleMessage = event => {\n if (transmuxer.currentTransmux !== options) {\n // disposed\n return;\n }\n\n if (event.data.action === 'data') {\n handleData_(event, transmuxedData, onData);\n }\n\n if (event.data.action === 'trackinfo') {\n onTrackInfo(event.data.trackInfo);\n }\n\n if (event.data.action === 'gopInfo') {\n handleGopInfo_(event, transmuxedData);\n }\n\n if (event.data.action === 'audioTimingInfo') {\n onAudioTimingInfo(event.data.audioTimingInfo);\n }\n\n if (event.data.action === 'videoTimingInfo') {\n onVideoTimingInfo(event.data.videoTimingInfo);\n }\n\n if (event.data.action === 'videoSegmentTimingInfo') {\n onVideoSegmentTimingInfo(event.data.videoSegmentTimingInfo);\n }\n\n if (event.data.action === 'audioSegmentTimingInfo') {\n onAudioSegmentTimingInfo(event.data.audioSegmentTimingInfo);\n }\n\n if (event.data.action === 'id3Frame') {\n onId3([event.data.id3Frame], event.data.id3Frame.dispatchType);\n }\n\n if (event.data.action === 'caption') {\n onCaptions(event.data.caption);\n }\n\n if (event.data.action === 'endedtimeline') {\n waitForEndedTimelineEvent = false;\n onEndedTimeline();\n }\n\n if (event.data.action === 'log') {\n onTransmuxerLog(event.data.log);\n } // wait for the transmuxed event since we may have audio and video\n\n\n if (event.data.type !== 'transmuxed') {\n return;\n } // If the \"endedtimeline\" event has not yet fired, and this segment represents the end\n // of a timeline, that means there may still be data events before the segment\n // processing can be considerred complete. In that case, the final event should be\n // an \"endedtimeline\" event with the type \"transmuxed.\"\n\n\n if (waitForEndedTimelineEvent) {\n return;\n }\n\n transmuxer.onmessage = null;\n handleDone_({\n transmuxedData,\n callback: onDone\n });\n /* eslint-disable no-use-before-define */\n\n dequeue(transmuxer);\n /* eslint-enable */\n };\n\n const handleError = () => {\n const error = {\n message: 'Received an error message from the transmuxer worker',\n metadata: {\n errorType: videojs.Error.StreamingFailedToTransmuxSegment,\n segmentInfo: segmentInfoPayload({\n segment\n })\n }\n };\n onDone(null, error);\n };\n\n transmuxer.onmessage = handleMessage;\n transmuxer.onerror = handleError;\n\n if (audioAppendStart) {\n transmuxer.postMessage({\n action: 'setAudioAppendStart',\n appendStart: audioAppendStart\n });\n } // allow empty arrays to be passed to clear out GOPs\n\n\n if (Array.isArray(gopsToAlignWith)) {\n transmuxer.postMessage({\n action: 'alignGopsWith',\n gopsToAlignWith\n });\n }\n\n if (typeof remux !== 'undefined') {\n transmuxer.postMessage({\n action: 'setRemux',\n remux\n });\n }\n\n if (bytes.byteLength) {\n const buffer = bytes instanceof ArrayBuffer ? bytes : bytes.buffer;\n const byteOffset = bytes instanceof ArrayBuffer ? 0 : bytes.byteOffset;\n triggerSegmentEventFn({\n type: 'segmenttransmuxingstart',\n segment\n });\n transmuxer.postMessage({\n action: 'push',\n // Send the typed-array of data as an ArrayBuffer so that\n // it can be sent as a \"Transferable\" and avoid the costly\n // memory copy\n data: buffer,\n // To recreate the original typed-array, we need information\n // about what portion of the ArrayBuffer it was a view into\n byteOffset,\n byteLength: bytes.byteLength\n }, [buffer]);\n }\n\n if (isEndOfTimeline) {\n transmuxer.postMessage({\n action: 'endTimeline'\n });\n } // even if we didn't push any bytes, we have to make sure we flush in case we reached\n // the end of the segment\n\n\n transmuxer.postMessage({\n action: 'flush'\n });\n};\nconst dequeue = transmuxer => {\n transmuxer.currentTransmux = null;\n\n if (transmuxer.transmuxQueue.length) {\n transmuxer.currentTransmux = transmuxer.transmuxQueue.shift();\n\n if (typeof transmuxer.currentTransmux === 'function') {\n transmuxer.currentTransmux();\n } else {\n processTransmux(transmuxer.currentTransmux);\n }\n }\n};\nconst processAction = (transmuxer, action) => {\n transmuxer.postMessage({\n action\n });\n dequeue(transmuxer);\n};\nconst enqueueAction = (action, transmuxer) => {\n if (!transmuxer.currentTransmux) {\n transmuxer.currentTransmux = action;\n processAction(transmuxer, action);\n return;\n }\n\n transmuxer.transmuxQueue.push(processAction.bind(null, transmuxer, action));\n};\nconst reset = transmuxer => {\n enqueueAction('reset', transmuxer);\n};\nconst endTimeline = transmuxer => {\n enqueueAction('endTimeline', transmuxer);\n};\nconst transmux = options => {\n if (!options.transmuxer.currentTransmux) {\n options.transmuxer.currentTransmux = options;\n processTransmux(options);\n return;\n }\n\n options.transmuxer.transmuxQueue.push(options);\n};\nconst createTransmuxer = options => {\n const transmuxer = new TransmuxWorker();\n transmuxer.currentTransmux = null;\n transmuxer.transmuxQueue = [];\n const term = transmuxer.terminate;\n\n transmuxer.terminate = () => {\n transmuxer.currentTransmux = null;\n transmuxer.transmuxQueue.length = 0;\n return term.call(transmuxer);\n };\n\n transmuxer.postMessage({\n action: 'init',\n options\n });\n return transmuxer;\n};\nvar segmentTransmuxer = {\n reset,\n endTimeline,\n transmux,\n createTransmuxer\n};\n\nconst workerCallback = function (options) {\n const transmuxer = options.transmuxer;\n const endAction = options.endAction || options.action;\n const callback = options.callback;\n\n const message = _extends({}, options, {\n endAction: null,\n transmuxer: null,\n callback: null\n });\n\n const listenForEndEvent = event => {\n if (event.data.action !== endAction) {\n return;\n }\n\n transmuxer.removeEventListener('message', listenForEndEvent); // transfer ownership of bytes back to us.\n\n if (event.data.data) {\n event.data.data = new Uint8Array(event.data.data, options.byteOffset || 0, options.byteLength || event.data.data.byteLength);\n\n if (options.data) {\n options.data = event.data.data;\n }\n }\n\n callback(event.data);\n };\n\n transmuxer.addEventListener('message', listenForEndEvent);\n\n if (options.data) {\n const isArrayBuffer = options.data instanceof ArrayBuffer;\n message.byteOffset = isArrayBuffer ? 0 : options.data.byteOffset;\n message.byteLength = options.data.byteLength;\n const transfers = [isArrayBuffer ? options.data : options.data.buffer];\n transmuxer.postMessage(message, transfers);\n } else {\n transmuxer.postMessage(message);\n }\n};\n\nconst REQUEST_ERRORS = {\n FAILURE: 2,\n TIMEOUT: -101,\n ABORTED: -102\n};\nconst WEB_VTT_CODEC = 'wvtt';\n/**\n * Abort all requests\n *\n * @param {Object} activeXhrs - an object that tracks all XHR requests\n */\n\nconst abortAll = activeXhrs => {\n activeXhrs.forEach(xhr => {\n xhr.abort();\n });\n};\n/**\n * Gather important bandwidth stats once a request has completed\n *\n * @param {Object} request - the XHR request from which to gather stats\n */\n\n\nconst getRequestStats = request => {\n return {\n bandwidth: request.bandwidth,\n bytesReceived: request.bytesReceived || 0,\n roundTripTime: request.roundTripTime || 0\n };\n};\n/**\n * If possible gather bandwidth stats as a request is in\n * progress\n *\n * @param {Event} progressEvent - an event object from an XHR's progress event\n */\n\n\nconst getProgressStats = progressEvent => {\n const request = progressEvent.target;\n const roundTripTime = Date.now() - request.requestTime;\n const stats = {\n bandwidth: Infinity,\n bytesReceived: 0,\n roundTripTime: roundTripTime || 0\n };\n stats.bytesReceived = progressEvent.loaded; // This can result in Infinity if stats.roundTripTime is 0 but that is ok\n // because we should only use bandwidth stats on progress to determine when\n // abort a request early due to insufficient bandwidth\n\n stats.bandwidth = Math.floor(stats.bytesReceived / stats.roundTripTime * 8 * 1000);\n return stats;\n};\n/**\n * Handle all error conditions in one place and return an object\n * with all the information\n *\n * @param {Error|null} error - if non-null signals an error occured with the XHR\n * @param {Object} request - the XHR request that possibly generated the error\n */\n\n\nconst handleErrors = (error, request) => {\n const {\n requestType\n } = request;\n const metadata = getStreamingNetworkErrorMetadata({\n requestType,\n request,\n error\n });\n\n if (request.timedout) {\n return {\n status: request.status,\n message: 'HLS request timed-out at URL: ' + request.uri,\n code: REQUEST_ERRORS.TIMEOUT,\n xhr: request,\n metadata\n };\n }\n\n if (request.aborted) {\n return {\n status: request.status,\n message: 'HLS request aborted at URL: ' + request.uri,\n code: REQUEST_ERRORS.ABORTED,\n xhr: request,\n metadata\n };\n }\n\n if (error) {\n return {\n status: request.status,\n message: 'HLS request errored at URL: ' + request.uri,\n code: REQUEST_ERRORS.FAILURE,\n xhr: request,\n metadata\n };\n }\n\n if (request.responseType === 'arraybuffer' && request.response.byteLength === 0) {\n return {\n status: request.status,\n message: 'Empty HLS response at URL: ' + request.uri,\n code: REQUEST_ERRORS.FAILURE,\n xhr: request,\n metadata\n };\n }\n\n return null;\n};\n/**\n * Handle responses for key data and convert the key data to the correct format\n * for the decryption step later\n *\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Array} objects - objects to add the key bytes to.\n * @param {Function} finishProcessingFn - a callback to execute to continue processing\n * this request\n */\n\n\nconst handleKeyResponse = (segment, objects, finishProcessingFn, triggerSegmentEventFn) => (error, request) => {\n const response = request.response;\n const errorObj = handleErrors(error, request);\n\n if (errorObj) {\n return finishProcessingFn(errorObj, segment);\n }\n\n if (response.byteLength !== 16) {\n return finishProcessingFn({\n status: request.status,\n message: 'Invalid HLS key at URL: ' + request.uri,\n code: REQUEST_ERRORS.FAILURE,\n xhr: request\n }, segment);\n }\n\n const view = new DataView(response);\n const bytes = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]);\n\n for (let i = 0; i < objects.length; i++) {\n objects[i].bytes = bytes;\n }\n\n const keyInfo = {\n uri: request.uri\n };\n triggerSegmentEventFn({\n type: 'segmentkeyloadcomplete',\n segment,\n keyInfo\n });\n return finishProcessingFn(null, segment);\n};\n/**\n * Processes an mp4 init segment depending on the codec through the transmuxer.\n *\n * @param {Object} segment init segment to process\n * @param {string} codec the codec of the text segments\n */\n\n\nconst initMp4Text = (segment, codec) => {\n if (codec === WEB_VTT_CODEC) {\n segment.transmuxer.postMessage({\n action: 'initMp4WebVttParser',\n data: segment.map.bytes\n });\n }\n};\n/**\n * Parses an mp4 text segment with the transmuxer and calls the doneFn from\n * the segment loader.\n *\n * @param {Object} segment the text segment to parse\n * @param {string} codec the codec of the text segment\n * @param {Function} doneFn the doneFn passed from the segment loader\n */\n\n\nconst parseMp4TextSegment = (segment, codec, doneFn) => {\n if (codec === WEB_VTT_CODEC) {\n workerCallback({\n action: 'getMp4WebVttText',\n data: segment.bytes,\n transmuxer: segment.transmuxer,\n callback: ({\n data,\n mp4VttCues\n }) => {\n segment.bytes = data;\n doneFn(null, segment, {\n mp4VttCues\n });\n }\n });\n }\n};\n\nconst parseInitSegment = (segment, callback) => {\n const type = detectContainerForBytes(segment.map.bytes); // TODO: We should also handle ts init segments here, but we\n // only know how to parse mp4 init segments at the moment\n\n if (type !== 'mp4') {\n const uri = segment.map.resolvedUri || segment.map.uri;\n const mediaType = type || 'unknown';\n return callback({\n internal: true,\n message: `Found unsupported ${mediaType} container for initialization segment at URL: ${uri}`,\n code: REQUEST_ERRORS.FAILURE,\n metadata: {\n mediaType\n }\n });\n }\n\n workerCallback({\n action: 'probeMp4Tracks',\n data: segment.map.bytes,\n transmuxer: segment.transmuxer,\n callback: ({\n tracks,\n data\n }) => {\n // transfer bytes back to us\n segment.map.bytes = data;\n tracks.forEach(function (track) {\n segment.map.tracks = segment.map.tracks || {}; // only support one track of each type for now\n\n if (segment.map.tracks[track.type]) {\n return;\n }\n\n segment.map.tracks[track.type] = track;\n\n if (typeof track.id === 'number' && track.timescale) {\n segment.map.timescales = segment.map.timescales || {};\n segment.map.timescales[track.id] = track.timescale;\n }\n\n if (track.type === 'text') {\n initMp4Text(segment, track.codec);\n }\n });\n return callback(null);\n }\n });\n};\n/**\n * Handle init-segment responses\n *\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Function} finishProcessingFn - a callback to execute to continue processing\n * this request\n */\n\n\nconst handleInitSegmentResponse = ({\n segment,\n finishProcessingFn,\n triggerSegmentEventFn\n}) => (error, request) => {\n const errorObj = handleErrors(error, request);\n\n if (errorObj) {\n return finishProcessingFn(errorObj, segment);\n }\n\n const bytes = new Uint8Array(request.response);\n triggerSegmentEventFn({\n type: 'segmentloaded',\n segment\n }); // init segment is encypted, we will have to wait\n // until the key request is done to decrypt.\n\n if (segment.map.key) {\n segment.map.encryptedBytes = bytes;\n return finishProcessingFn(null, segment);\n }\n\n segment.map.bytes = bytes;\n parseInitSegment(segment, function (parseError) {\n if (parseError) {\n parseError.xhr = request;\n parseError.status = request.status;\n return finishProcessingFn(parseError, segment);\n }\n\n finishProcessingFn(null, segment);\n });\n};\n/**\n * Response handler for segment-requests being sure to set the correct\n * property depending on whether the segment is encryped or not\n * Also records and keeps track of stats that are used for ABR purposes\n *\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Function} finishProcessingFn - a callback to execute to continue processing\n * this request\n */\n\n\nconst handleSegmentResponse = ({\n segment,\n finishProcessingFn,\n responseType,\n triggerSegmentEventFn\n}) => (error, request) => {\n const errorObj = handleErrors(error, request);\n\n if (errorObj) {\n return finishProcessingFn(errorObj, segment);\n }\n\n triggerSegmentEventFn({\n type: 'segmentloaded',\n segment\n });\n const newBytes = // although responseText \"should\" exist, this guard serves to prevent an error being\n // thrown for two primary cases:\n // 1. the mime type override stops working, or is not implemented for a specific\n // browser\n // 2. when using mock XHR libraries like sinon that do not allow the override behavior\n responseType === 'arraybuffer' || !request.responseText ? request.response : stringToArrayBuffer(request.responseText.substring(segment.lastReachedChar || 0));\n segment.stats = getRequestStats(request);\n\n if (segment.key) {\n segment.encryptedBytes = new Uint8Array(newBytes);\n } else {\n segment.bytes = new Uint8Array(newBytes);\n }\n\n return finishProcessingFn(null, segment);\n};\n\nconst transmuxAndNotify = ({\n segment,\n bytes,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n}) => {\n const fmp4Tracks = segment.map && segment.map.tracks || {};\n const isMuxed = Boolean(fmp4Tracks.audio && fmp4Tracks.video); // Keep references to each function so we can null them out after we're done with them.\n // One reason for this is that in the case of full segments, we want to trust start\n // times from the probe, rather than the transmuxer.\n\n let audioStartFn = timingInfoFn.bind(null, segment, 'audio', 'start');\n const audioEndFn = timingInfoFn.bind(null, segment, 'audio', 'end');\n let videoStartFn = timingInfoFn.bind(null, segment, 'video', 'start');\n const videoEndFn = timingInfoFn.bind(null, segment, 'video', 'end');\n\n const finish = () => transmux({\n bytes,\n transmuxer: segment.transmuxer,\n audioAppendStart: segment.audioAppendStart,\n gopsToAlignWith: segment.gopsToAlignWith,\n remux: isMuxed,\n onData: result => {\n result.type = result.type === 'combined' ? 'video' : result.type;\n dataFn(segment, result);\n },\n onTrackInfo: trackInfo => {\n if (trackInfoFn) {\n if (isMuxed) {\n trackInfo.isMuxed = true;\n }\n\n trackInfoFn(segment, trackInfo);\n }\n },\n onAudioTimingInfo: audioTimingInfo => {\n // we only want the first start value we encounter\n if (audioStartFn && typeof audioTimingInfo.start !== 'undefined') {\n audioStartFn(audioTimingInfo.start);\n audioStartFn = null;\n } // we want to continually update the end time\n\n\n if (audioEndFn && typeof audioTimingInfo.end !== 'undefined') {\n audioEndFn(audioTimingInfo.end);\n }\n },\n onVideoTimingInfo: videoTimingInfo => {\n // we only want the first start value we encounter\n if (videoStartFn && typeof videoTimingInfo.start !== 'undefined') {\n videoStartFn(videoTimingInfo.start);\n videoStartFn = null;\n } // we want to continually update the end time\n\n\n if (videoEndFn && typeof videoTimingInfo.end !== 'undefined') {\n videoEndFn(videoTimingInfo.end);\n }\n },\n onVideoSegmentTimingInfo: videoSegmentTimingInfo => {\n const timingInfo = {\n pts: {\n start: videoSegmentTimingInfo.start.presentation,\n end: videoSegmentTimingInfo.end.presentation\n },\n dts: {\n start: videoSegmentTimingInfo.start.decode,\n end: videoSegmentTimingInfo.end.decode\n }\n };\n triggerSegmentEventFn({\n type: 'segmenttransmuxingtiminginfoavailable',\n segment,\n timingInfo\n });\n videoSegmentTimingInfoFn(videoSegmentTimingInfo);\n },\n onAudioSegmentTimingInfo: audioSegmentTimingInfo => {\n const timingInfo = {\n pts: {\n start: audioSegmentTimingInfo.start.pts,\n end: audioSegmentTimingInfo.end.pts\n },\n dts: {\n start: audioSegmentTimingInfo.start.dts,\n end: audioSegmentTimingInfo.end.dts\n }\n };\n triggerSegmentEventFn({\n type: 'segmenttransmuxingtiminginfoavailable',\n segment,\n timingInfo\n });\n audioSegmentTimingInfoFn(audioSegmentTimingInfo);\n },\n onId3: (id3Frames, dispatchType) => {\n id3Fn(segment, id3Frames, dispatchType);\n },\n onCaptions: captions => {\n captionsFn(segment, [captions]);\n },\n isEndOfTimeline,\n onEndedTimeline: () => {\n endedTimelineFn();\n },\n onTransmuxerLog,\n onDone: (result, error) => {\n if (!doneFn) {\n return;\n }\n\n result.type = result.type === 'combined' ? 'video' : result.type;\n triggerSegmentEventFn({\n type: 'segmenttransmuxingcomplete',\n segment\n });\n doneFn(error, segment, result);\n },\n segment,\n triggerSegmentEventFn\n }); // In the transmuxer, we don't yet have the ability to extract a \"proper\" start time.\n // Meaning cached frame data may corrupt our notion of where this segment\n // really starts. To get around this, probe for the info needed.\n\n\n workerCallback({\n action: 'probeTs',\n transmuxer: segment.transmuxer,\n data: bytes,\n baseStartTime: segment.baseStartTime,\n callback: data => {\n segment.bytes = bytes = data.data;\n const probeResult = data.result;\n\n if (probeResult) {\n trackInfoFn(segment, {\n hasAudio: probeResult.hasAudio,\n hasVideo: probeResult.hasVideo,\n isMuxed\n });\n trackInfoFn = null;\n }\n\n finish();\n }\n });\n};\n\nconst handleSegmentBytes = ({\n segment,\n bytes,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n}) => {\n let bytesAsUint8Array = new Uint8Array(bytes); // TODO:\n // We should have a handler that fetches the number of bytes required\n // to check if something is fmp4. This will allow us to save bandwidth\n // because we can only exclude a playlist and abort requests\n // by codec after trackinfo triggers.\n\n if (isLikelyFmp4MediaSegment(bytesAsUint8Array)) {\n segment.isFmp4 = true;\n const {\n tracks\n } = segment.map;\n const isMp4TextSegment = tracks.text && (!tracks.audio || !tracks.video);\n\n if (isMp4TextSegment) {\n dataFn(segment, {\n data: bytesAsUint8Array,\n type: 'text'\n });\n parseMp4TextSegment(segment, tracks.text.codec, doneFn);\n return;\n }\n\n const trackInfo = {\n isFmp4: true,\n hasVideo: !!tracks.video,\n hasAudio: !!tracks.audio\n }; // if we have a audio track, with a codec that is not set to\n // encrypted audio\n\n if (tracks.audio && tracks.audio.codec && tracks.audio.codec !== 'enca') {\n trackInfo.audioCodec = tracks.audio.codec;\n } // if we have a video track, with a codec that is not set to\n // encrypted video\n\n\n if (tracks.video && tracks.video.codec && tracks.video.codec !== 'encv') {\n trackInfo.videoCodec = tracks.video.codec;\n }\n\n if (tracks.video && tracks.audio) {\n trackInfo.isMuxed = true;\n } // since we don't support appending fmp4 data on progress, we know we have the full\n // segment here\n\n\n trackInfoFn(segment, trackInfo); // The probe doesn't provide the segment end time, so only callback with the start\n // time. The end time can be roughly calculated by the receiver using the duration.\n //\n // Note that the start time returned by the probe reflects the baseMediaDecodeTime, as\n // that is the true start of the segment (where the playback engine should begin\n // decoding).\n\n const finishLoading = (captions, id3Frames) => {\n // if the track still has audio at this point it is only possible\n // for it to be audio only. See `tracks.video && tracks.audio` if statement\n // above.\n // we make sure to use segment.bytes here as that\n dataFn(segment, {\n data: bytesAsUint8Array,\n type: trackInfo.hasAudio && !trackInfo.isMuxed ? 'audio' : 'video'\n });\n\n if (id3Frames && id3Frames.length) {\n id3Fn(segment, id3Frames);\n }\n\n if (captions && captions.length) {\n captionsFn(segment, captions);\n }\n\n doneFn(null, segment, {});\n };\n\n workerCallback({\n action: 'probeMp4StartTime',\n timescales: segment.map.timescales,\n data: bytesAsUint8Array,\n transmuxer: segment.transmuxer,\n callback: ({\n data,\n startTime\n }) => {\n // transfer bytes back to us\n bytes = data.buffer;\n segment.bytes = bytesAsUint8Array = data;\n\n if (trackInfo.hasAudio && !trackInfo.isMuxed) {\n timingInfoFn(segment, 'audio', 'start', startTime);\n }\n\n if (trackInfo.hasVideo) {\n timingInfoFn(segment, 'video', 'start', startTime);\n }\n\n workerCallback({\n action: 'probeEmsgID3',\n data: bytesAsUint8Array,\n transmuxer: segment.transmuxer,\n offset: startTime,\n callback: ({\n emsgData,\n id3Frames\n }) => {\n // transfer bytes back to us\n bytes = emsgData.buffer;\n segment.bytes = bytesAsUint8Array = emsgData; // Run through the CaptionParser in case there are captions.\n // Initialize CaptionParser if it hasn't been yet\n\n if (!tracks.video || !emsgData.byteLength || !segment.transmuxer) {\n finishLoading(undefined, id3Frames);\n return;\n }\n\n workerCallback({\n action: 'pushMp4Captions',\n endAction: 'mp4Captions',\n transmuxer: segment.transmuxer,\n data: bytesAsUint8Array,\n timescales: segment.map.timescales,\n trackIds: [tracks.video.id],\n callback: message => {\n // transfer bytes back to us\n bytes = message.data.buffer;\n segment.bytes = bytesAsUint8Array = message.data;\n message.logs.forEach(function (log) {\n onTransmuxerLog(merge(log, {\n stream: 'mp4CaptionParser'\n }));\n });\n finishLoading(message.captions, id3Frames);\n }\n });\n }\n });\n }\n });\n return;\n } // VTT or other segments that don't need processing\n\n\n if (!segment.transmuxer) {\n doneFn(null, segment, {});\n return;\n }\n\n if (typeof segment.container === 'undefined') {\n segment.container = detectContainerForBytes(bytesAsUint8Array);\n }\n\n if (segment.container !== 'ts' && segment.container !== 'aac') {\n trackInfoFn(segment, {\n hasAudio: false,\n hasVideo: false\n });\n doneFn(null, segment, {});\n return;\n } // ts or aac\n\n\n transmuxAndNotify({\n segment,\n bytes,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n });\n};\n\nconst decrypt = function ({\n id,\n key,\n encryptedBytes,\n decryptionWorker,\n segment,\n doneFn\n}, callback) {\n const decryptionHandler = event => {\n if (event.data.source === id) {\n decryptionWorker.removeEventListener('message', decryptionHandler);\n const decrypted = event.data.decrypted;\n callback(new Uint8Array(decrypted.bytes, decrypted.byteOffset, decrypted.byteLength));\n }\n };\n\n decryptionWorker.onerror = () => {\n const message = 'An error occurred in the decryption worker';\n const segmentInfo = segmentInfoPayload({\n segment\n });\n const decryptError = {\n message,\n metadata: {\n error: new Error(message),\n errorType: videojs.Error.StreamingFailedToDecryptSegment,\n segmentInfo,\n keyInfo: {\n uri: segment.key.resolvedUri || segment.map.key.resolvedUri\n }\n }\n };\n doneFn(decryptError, segment);\n };\n\n decryptionWorker.addEventListener('message', decryptionHandler);\n let keyBytes;\n\n if (key.bytes.slice) {\n keyBytes = key.bytes.slice();\n } else {\n keyBytes = new Uint32Array(Array.prototype.slice.call(key.bytes));\n } // incrementally decrypt the bytes\n\n\n decryptionWorker.postMessage(createTransferableMessage({\n source: id,\n encrypted: encryptedBytes,\n key: keyBytes,\n iv: key.iv\n }), [encryptedBytes.buffer, keyBytes.buffer]);\n};\n/**\n * Decrypt the segment via the decryption web worker\n *\n * @param {WebWorker} decryptionWorker - a WebWorker interface to AES-128 decryption\n * routines\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Function} trackInfoFn - a callback that receives track info\n * @param {Function} timingInfoFn - a callback that receives timing info\n * @param {Function} videoSegmentTimingInfoFn\n * a callback that receives video timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} audioSegmentTimingInfoFn\n * a callback that receives audio timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {boolean} isEndOfTimeline\n * true if this segment represents the last segment in a timeline\n * @param {Function} endedTimelineFn\n * a callback made when a timeline is ended, will only be called if\n * isEndOfTimeline is true\n * @param {Function} dataFn - a callback that is executed when segment bytes are available\n * and ready to use\n * @param {Function} doneFn - a callback that is executed after decryption has completed\n */\n\n\nconst decryptSegment = ({\n decryptionWorker,\n segment,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n}) => {\n triggerSegmentEventFn({\n type: 'segmentdecryptionstart'\n });\n decrypt({\n id: segment.requestId,\n key: segment.key,\n encryptedBytes: segment.encryptedBytes,\n decryptionWorker,\n segment,\n doneFn\n }, decryptedBytes => {\n segment.bytes = decryptedBytes;\n triggerSegmentEventFn({\n type: 'segmentdecryptioncomplete',\n segment\n });\n handleSegmentBytes({\n segment,\n bytes: segment.bytes,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n });\n });\n};\n/**\n * This function waits for all XHRs to finish (with either success or failure)\n * before continueing processing via it's callback. The function gathers errors\n * from each request into a single errors array so that the error status for\n * each request can be examined later.\n *\n * @param {Object} activeXhrs - an object that tracks all XHR requests\n * @param {WebWorker} decryptionWorker - a WebWorker interface to AES-128 decryption\n * routines\n * @param {Function} trackInfoFn - a callback that receives track info\n * @param {Function} timingInfoFn - a callback that receives timing info\n * @param {Function} videoSegmentTimingInfoFn\n * a callback that receives video timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} audioSegmentTimingInfoFn\n * a callback that receives audio timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} id3Fn - a callback that receives ID3 metadata\n * @param {Function} captionsFn - a callback that receives captions\n * @param {boolean} isEndOfTimeline\n * true if this segment represents the last segment in a timeline\n * @param {Function} endedTimelineFn\n * a callback made when a timeline is ended, will only be called if\n * isEndOfTimeline is true\n * @param {Function} dataFn - a callback that is executed when segment bytes are available\n * and ready to use\n * @param {Function} doneFn - a callback that is executed after all resources have been\n * downloaded and any decryption completed\n */\n\n\nconst waitForCompletion = ({\n activeXhrs,\n decryptionWorker,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n}) => {\n let count = 0;\n let didError = false;\n return (error, segment) => {\n if (didError) {\n return;\n }\n\n if (error) {\n didError = true; // If there are errors, we have to abort any outstanding requests\n\n abortAll(activeXhrs); // Even though the requests above are aborted, and in theory we could wait until we\n // handle the aborted events from those requests, there are some cases where we may\n // never get an aborted event. For instance, if the network connection is lost and\n // there were two requests, the first may have triggered an error immediately, while\n // the second request remains unsent. In that case, the aborted algorithm will not\n // trigger an abort: see https://xhr.spec.whatwg.org/#the-abort()-method\n //\n // We also can't rely on the ready state of the XHR, since the request that\n // triggered the connection error may also show as a ready state of 0 (unsent).\n // Therefore, we have to finish this group of requests immediately after the first\n // seen error.\n\n return doneFn(error, segment);\n }\n\n count += 1;\n\n if (count === activeXhrs.length) {\n const segmentFinish = function () {\n if (segment.encryptedBytes) {\n return decryptSegment({\n decryptionWorker,\n segment,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n });\n } // Otherwise, everything is ready just continue\n\n\n handleSegmentBytes({\n segment,\n bytes: segment.bytes,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n });\n }; // Keep track of when *all* of the requests have completed\n\n\n segment.endOfAllRequests = Date.now();\n\n if (segment.map && segment.map.encryptedBytes && !segment.map.bytes) {\n triggerSegmentEventFn({\n type: 'segmentdecryptionstart',\n segment\n });\n return decrypt({\n decryptionWorker,\n // add -init to the \"id\" to differentiate between segment\n // and init segment decryption, just in case they happen\n // at the same time at some point in the future.\n id: segment.requestId + '-init',\n encryptedBytes: segment.map.encryptedBytes,\n key: segment.map.key,\n segment,\n doneFn\n }, decryptedBytes => {\n segment.map.bytes = decryptedBytes;\n triggerSegmentEventFn({\n type: 'segmentdecryptioncomplete',\n segment\n });\n parseInitSegment(segment, parseError => {\n if (parseError) {\n abortAll(activeXhrs);\n return doneFn(parseError, segment);\n }\n\n segmentFinish();\n });\n });\n }\n\n segmentFinish();\n }\n };\n};\n/**\n * Calls the abort callback if any request within the batch was aborted. Will only call\n * the callback once per batch of requests, even if multiple were aborted.\n *\n * @param {Object} loadendState - state to check to see if the abort function was called\n * @param {Function} abortFn - callback to call for abort\n */\n\n\nconst handleLoadEnd = ({\n loadendState,\n abortFn\n}) => event => {\n const request = event.target;\n\n if (request.aborted && abortFn && !loadendState.calledAbortFn) {\n abortFn();\n loadendState.calledAbortFn = true;\n }\n};\n/**\n * Simple progress event callback handler that gathers some stats before\n * executing a provided callback with the `segment` object\n *\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Function} progressFn - a callback that is executed each time a progress event\n * is received\n * @param {Function} trackInfoFn - a callback that receives track info\n * @param {Function} timingInfoFn - a callback that receives timing info\n * @param {Function} videoSegmentTimingInfoFn\n * a callback that receives video timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} audioSegmentTimingInfoFn\n * a callback that receives audio timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {boolean} isEndOfTimeline\n * true if this segment represents the last segment in a timeline\n * @param {Function} endedTimelineFn\n * a callback made when a timeline is ended, will only be called if\n * isEndOfTimeline is true\n * @param {Function} dataFn - a callback that is executed when segment bytes are available\n * and ready to use\n * @param {Event} event - the progress event object from XMLHttpRequest\n */\n\n\nconst handleProgress = ({\n segment,\n progressFn,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn\n}) => event => {\n const request = event.target;\n\n if (request.aborted) {\n return;\n }\n\n segment.stats = merge(segment.stats, getProgressStats(event)); // record the time that we receive the first byte of data\n\n if (!segment.stats.firstBytesReceivedAt && segment.stats.bytesReceived) {\n segment.stats.firstBytesReceivedAt = Date.now();\n }\n\n return progressFn(event, segment);\n};\n/**\n * Load all resources and does any processing necessary for a media-segment\n *\n * Features:\n * decrypts the media-segment if it has a key uri and an iv\n * aborts *all* requests if *any* one request fails\n *\n * The segment object, at minimum, has the following format:\n * {\n * resolvedUri: String,\n * [transmuxer]: Object,\n * [byterange]: {\n * offset: Number,\n * length: Number\n * },\n * [key]: {\n * resolvedUri: String\n * [byterange]: {\n * offset: Number,\n * length: Number\n * },\n * iv: {\n * bytes: Uint32Array\n * }\n * },\n * [map]: {\n * resolvedUri: String,\n * [byterange]: {\n * offset: Number,\n * length: Number\n * },\n * [bytes]: Uint8Array\n * }\n * }\n * ...where [name] denotes optional properties\n *\n * @param {Function} xhr - an instance of the xhr wrapper in xhr.js\n * @param {Object} xhrOptions - the base options to provide to all xhr requests\n * @param {WebWorker} decryptionWorker - a WebWorker interface to AES-128\n * decryption routines\n * @param {Object} segment - a simplified copy of the segmentInfo object\n * from SegmentLoader\n * @param {Function} abortFn - a callback called (only once) if any piece of a request was\n * aborted\n * @param {Function} progressFn - a callback that receives progress events from the main\n * segment's xhr request\n * @param {Function} trackInfoFn - a callback that receives track info\n * @param {Function} timingInfoFn - a callback that receives timing info\n * @param {Function} videoSegmentTimingInfoFn\n * a callback that receives video timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} audioSegmentTimingInfoFn\n * a callback that receives audio timing info based on media times and\n * any adjustments made by the transmuxer\n * @param {Function} id3Fn - a callback that receives ID3 metadata\n * @param {Function} captionsFn - a callback that receives captions\n * @param {boolean} isEndOfTimeline\n * true if this segment represents the last segment in a timeline\n * @param {Function} endedTimelineFn\n * a callback made when a timeline is ended, will only be called if\n * isEndOfTimeline is true\n * @param {Function} dataFn - a callback that receives data from the main segment's xhr\n * request, transmuxed if needed\n * @param {Function} doneFn - a callback that is executed only once all requests have\n * succeeded or failed\n * @return {Function} a function that, when invoked, immediately aborts all\n * outstanding requests\n */\n\n\nconst mediaSegmentRequest = ({\n xhr,\n xhrOptions,\n decryptionWorker,\n segment,\n abortFn,\n progressFn,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n}) => {\n const activeXhrs = [];\n const finishProcessingFn = waitForCompletion({\n activeXhrs,\n decryptionWorker,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn,\n doneFn,\n onTransmuxerLog,\n triggerSegmentEventFn\n }); // optionally, request the decryption key\n\n if (segment.key && !segment.key.bytes) {\n const objects = [segment.key];\n\n if (segment.map && !segment.map.bytes && segment.map.key && segment.map.key.resolvedUri === segment.key.resolvedUri) {\n objects.push(segment.map.key);\n }\n\n const keyRequestOptions = merge(xhrOptions, {\n uri: segment.key.resolvedUri,\n responseType: 'arraybuffer',\n requestType: 'segment-key'\n });\n const keyRequestCallback = handleKeyResponse(segment, objects, finishProcessingFn, triggerSegmentEventFn);\n const keyInfo = {\n uri: segment.key.resolvedUri\n };\n triggerSegmentEventFn({\n type: 'segmentkeyloadstart',\n segment,\n keyInfo\n });\n const keyXhr = xhr(keyRequestOptions, keyRequestCallback);\n activeXhrs.push(keyXhr);\n } // optionally, request the associated media init segment\n\n\n if (segment.map && !segment.map.bytes) {\n const differentMapKey = segment.map.key && (!segment.key || segment.key.resolvedUri !== segment.map.key.resolvedUri);\n\n if (differentMapKey) {\n const mapKeyRequestOptions = merge(xhrOptions, {\n uri: segment.map.key.resolvedUri,\n responseType: 'arraybuffer',\n requestType: 'segment-key'\n });\n const mapKeyRequestCallback = handleKeyResponse(segment, [segment.map.key], finishProcessingFn, triggerSegmentEventFn);\n const keyInfo = {\n uri: segment.map.key.resolvedUri\n };\n triggerSegmentEventFn({\n type: 'segmentkeyloadstart',\n segment,\n keyInfo\n });\n const mapKeyXhr = xhr(mapKeyRequestOptions, mapKeyRequestCallback);\n activeXhrs.push(mapKeyXhr);\n }\n\n const initSegmentOptions = merge(xhrOptions, {\n uri: segment.map.resolvedUri,\n responseType: 'arraybuffer',\n headers: segmentXhrHeaders(segment.map),\n requestType: 'segment-media-initialization'\n });\n const initSegmentRequestCallback = handleInitSegmentResponse({\n segment,\n finishProcessingFn,\n triggerSegmentEventFn\n });\n triggerSegmentEventFn({\n type: 'segmentloadstart',\n segment\n });\n const initSegmentXhr = xhr(initSegmentOptions, initSegmentRequestCallback);\n activeXhrs.push(initSegmentXhr);\n }\n\n const segmentRequestOptions = merge(xhrOptions, {\n uri: segment.part && segment.part.resolvedUri || segment.resolvedUri,\n responseType: 'arraybuffer',\n headers: segmentXhrHeaders(segment),\n requestType: 'segment'\n });\n const segmentRequestCallback = handleSegmentResponse({\n segment,\n finishProcessingFn,\n responseType: segmentRequestOptions.responseType,\n triggerSegmentEventFn\n });\n triggerSegmentEventFn({\n type: 'segmentloadstart',\n segment\n });\n const segmentXhr = xhr(segmentRequestOptions, segmentRequestCallback);\n segmentXhr.addEventListener('progress', handleProgress({\n segment,\n progressFn,\n trackInfoFn,\n timingInfoFn,\n videoSegmentTimingInfoFn,\n audioSegmentTimingInfoFn,\n id3Fn,\n captionsFn,\n isEndOfTimeline,\n endedTimelineFn,\n dataFn\n }));\n activeXhrs.push(segmentXhr); // since all parts of the request must be considered, but should not make callbacks\n // multiple times, provide a shared state object\n\n const loadendState = {};\n activeXhrs.forEach(activeXhr => {\n activeXhr.addEventListener('loadend', handleLoadEnd({\n loadendState,\n abortFn\n }));\n });\n return () => abortAll(activeXhrs);\n};\n\n/**\n * @file - codecs.js - Handles tasks regarding codec strings such as translating them to\n * codec strings, or translating codec strings into objects that can be examined.\n */\nconst logFn$1 = logger('CodecUtils');\n/**\n * Returns a set of codec strings parsed from the playlist or the default\n * codec strings if no codecs were specified in the playlist\n *\n * @param {Playlist} media the current media playlist\n * @return {Object} an object with the video and audio codecs\n */\n\nconst getCodecs = function (media) {\n // if the codecs were explicitly specified, use them instead of the\n // defaults\n const mediaAttributes = media.attributes || {};\n\n if (mediaAttributes.CODECS) {\n return parseCodecs(mediaAttributes.CODECS);\n }\n};\n\nconst isMaat = (main, media) => {\n const mediaAttributes = media.attributes || {};\n return main && main.mediaGroups && main.mediaGroups.AUDIO && mediaAttributes.AUDIO && main.mediaGroups.AUDIO[mediaAttributes.AUDIO];\n};\nconst isMuxed = (main, media) => {\n if (!isMaat(main, media)) {\n return true;\n }\n\n const mediaAttributes = media.attributes || {};\n const audioGroup = main.mediaGroups.AUDIO[mediaAttributes.AUDIO];\n\n for (const groupId in audioGroup) {\n // If an audio group has a URI (the case for HLS, as HLS will use external playlists),\n // or there are listed playlists (the case for DASH, as the manifest will have already\n // provided all of the details necessary to generate the audio playlist, as opposed to\n // HLS' externally requested playlists), then the content is demuxed.\n if (!audioGroup[groupId].uri && !audioGroup[groupId].playlists) {\n return true;\n }\n }\n\n return false;\n};\nconst unwrapCodecList = function (codecList) {\n const codecs = {};\n codecList.forEach(({\n mediaType,\n type,\n details\n }) => {\n codecs[mediaType] = codecs[mediaType] || [];\n codecs[mediaType].push(translateLegacyCodec(`${type}${details}`));\n });\n Object.keys(codecs).forEach(function (mediaType) {\n if (codecs[mediaType].length > 1) {\n logFn$1(`multiple ${mediaType} codecs found as attributes: ${codecs[mediaType].join(', ')}. Setting playlist codecs to null so that we wait for mux.js to probe segments for real codecs.`);\n codecs[mediaType] = null;\n return;\n }\n\n codecs[mediaType] = codecs[mediaType][0];\n });\n return codecs;\n};\nconst codecCount = function (codecObj) {\n let count = 0;\n\n if (codecObj.audio) {\n count++;\n }\n\n if (codecObj.video) {\n count++;\n }\n\n return count;\n};\n/**\n * Calculates the codec strings for a working configuration of\n * SourceBuffers to play variant streams in a main playlist. If\n * there is no possible working configuration, an empty object will be\n * returned.\n *\n * @param main {Object} the m3u8 object for the main playlist\n * @param media {Object} the m3u8 object for the variant playlist\n * @return {Object} the codec strings.\n *\n * @private\n */\n\nconst codecsForPlaylist = function (main, media) {\n const mediaAttributes = media.attributes || {};\n const codecInfo = unwrapCodecList(getCodecs(media) || []); // HLS with multiple-audio tracks must always get an audio codec.\n // Put another way, there is no way to have a video-only multiple-audio HLS!\n\n if (isMaat(main, media) && !codecInfo.audio) {\n if (!isMuxed(main, media)) {\n // It is possible for codecs to be specified on the audio media group playlist but\n // not on the rendition playlist. This is mostly the case for DASH, where audio and\n // video are always separate (and separately specified).\n const defaultCodecs = unwrapCodecList(codecsFromDefault(main, mediaAttributes.AUDIO) || []);\n\n if (defaultCodecs.audio) {\n codecInfo.audio = defaultCodecs.audio;\n }\n }\n }\n\n return codecInfo;\n};\n\nconst logFn = logger('PlaylistSelector');\n\nconst representationToString = function (representation) {\n if (!representation || !representation.playlist) {\n return;\n }\n\n const playlist = representation.playlist;\n return JSON.stringify({\n id: playlist.id,\n bandwidth: representation.bandwidth,\n width: representation.width,\n height: representation.height,\n codecs: playlist.attributes && playlist.attributes.CODECS || ''\n });\n}; // Utilities\n\n/**\n * Returns the CSS value for the specified property on an element\n * using `getComputedStyle`. Firefox has a long-standing issue where\n * getComputedStyle() may return null when running in an iframe with\n * `display: none`.\n *\n * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n * @param {HTMLElement} el the htmlelement to work on\n * @param {string} the proprety to get the style for\n */\n\n\nconst safeGetComputedStyle = function (el, property) {\n if (!el) {\n return '';\n }\n\n const result = window$1.getComputedStyle(el);\n\n if (!result) {\n return '';\n }\n\n return result[property];\n};\n/**\n * Resuable stable sort function\n *\n * @param {Playlists} array\n * @param {Function} sortFn Different comparators\n * @function stableSort\n */\n\n\nconst stableSort = function (array, sortFn) {\n const newArray = array.slice();\n array.sort(function (left, right) {\n const cmp = sortFn(left, right);\n\n if (cmp === 0) {\n return newArray.indexOf(left) - newArray.indexOf(right);\n }\n\n return cmp;\n });\n};\n/**\n * A comparator function to sort two playlist object by bandwidth.\n *\n * @param {Object} left a media playlist object\n * @param {Object} right a media playlist object\n * @return {number} Greater than zero if the bandwidth attribute of\n * left is greater than the corresponding attribute of right. Less\n * than zero if the bandwidth of right is greater than left and\n * exactly zero if the two are equal.\n */\n\n\nconst comparePlaylistBandwidth = function (left, right) {\n let leftBandwidth;\n let rightBandwidth;\n\n if (left.attributes.BANDWIDTH) {\n leftBandwidth = left.attributes.BANDWIDTH;\n }\n\n leftBandwidth = leftBandwidth || window$1.Number.MAX_VALUE;\n\n if (right.attributes.BANDWIDTH) {\n rightBandwidth = right.attributes.BANDWIDTH;\n }\n\n rightBandwidth = rightBandwidth || window$1.Number.MAX_VALUE;\n return leftBandwidth - rightBandwidth;\n};\n/**\n * A comparator function to sort two playlist object by resolution (width).\n *\n * @param {Object} left a media playlist object\n * @param {Object} right a media playlist object\n * @return {number} Greater than zero if the resolution.width attribute of\n * left is greater than the corresponding attribute of right. Less\n * than zero if the resolution.width of right is greater than left and\n * exactly zero if the two are equal.\n */\n\nconst comparePlaylistResolution = function (left, right) {\n let leftWidth;\n let rightWidth;\n\n if (left.attributes.RESOLUTION && left.attributes.RESOLUTION.width) {\n leftWidth = left.attributes.RESOLUTION.width;\n }\n\n leftWidth = leftWidth || window$1.Number.MAX_VALUE;\n\n if (right.attributes.RESOLUTION && right.attributes.RESOLUTION.width) {\n rightWidth = right.attributes.RESOLUTION.width;\n }\n\n rightWidth = rightWidth || window$1.Number.MAX_VALUE; // NOTE - Fallback to bandwidth sort as appropriate in cases where multiple renditions\n // have the same media dimensions/ resolution\n\n if (leftWidth === rightWidth && left.attributes.BANDWIDTH && right.attributes.BANDWIDTH) {\n return left.attributes.BANDWIDTH - right.attributes.BANDWIDTH;\n }\n\n return leftWidth - rightWidth;\n};\n/**\n * Chooses the appropriate media playlist based on bandwidth and player size\n *\n * @param {Object} main\n * Object representation of the main manifest\n * @param {number} playerBandwidth\n * Current calculated bandwidth of the player\n * @param {number} playerWidth\n * Current width of the player element (should account for the device pixel ratio)\n * @param {number} playerHeight\n * Current height of the player element (should account for the device pixel ratio)\n * @param {boolean} limitRenditionByPlayerDimensions\n * True if the player width and height should be used during the selection, false otherwise\n * @param {Object} playlistController\n * the current playlistController object\n * @return {Playlist} the highest bitrate playlist less than the\n * currently detected bandwidth, accounting for some amount of\n * bandwidth variance\n */\n\nlet simpleSelector = function (main, playerBandwidth, playerWidth, playerHeight, limitRenditionByPlayerDimensions, playlistController) {\n // If we end up getting called before `main` is available, exit early\n if (!main) {\n return;\n }\n\n const options = {\n bandwidth: playerBandwidth,\n width: playerWidth,\n height: playerHeight,\n limitRenditionByPlayerDimensions\n };\n let playlists = main.playlists; // if playlist is audio only, select between currently active audio group playlists.\n\n if (Playlist.isAudioOnly(main)) {\n playlists = playlistController.getAudioTrackPlaylists_(); // add audioOnly to options so that we log audioOnly: true\n // at the buttom of this function for debugging.\n\n options.audioOnly = true;\n } // convert the playlists to an intermediary representation to make comparisons easier\n\n\n let sortedPlaylistReps = playlists.map(playlist => {\n let bandwidth;\n const width = playlist.attributes && playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.width;\n const height = playlist.attributes && playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.height;\n bandwidth = playlist.attributes && playlist.attributes.BANDWIDTH;\n bandwidth = bandwidth || window$1.Number.MAX_VALUE;\n return {\n bandwidth,\n width,\n height,\n playlist\n };\n });\n stableSort(sortedPlaylistReps, (left, right) => left.bandwidth - right.bandwidth); // filter out any playlists that have been excluded due to\n // incompatible configurations\n\n sortedPlaylistReps = sortedPlaylistReps.filter(rep => !Playlist.isIncompatible(rep.playlist)); // filter out any playlists that have been disabled manually through the representations\n // api or excluded temporarily due to playback errors.\n\n let enabledPlaylistReps = sortedPlaylistReps.filter(rep => Playlist.isEnabled(rep.playlist));\n\n if (!enabledPlaylistReps.length) {\n // if there are no enabled playlists, then they have all been excluded or disabled\n // by the user through the representations api. In this case, ignore exclusion and\n // fallback to what the user wants by using playlists the user has not disabled.\n enabledPlaylistReps = sortedPlaylistReps.filter(rep => !Playlist.isDisabled(rep.playlist));\n } // filter out any variant that has greater effective bitrate\n // than the current estimated bandwidth\n\n\n const bandwidthPlaylistReps = enabledPlaylistReps.filter(rep => rep.bandwidth * Config.BANDWIDTH_VARIANCE < playerBandwidth);\n let highestRemainingBandwidthRep = bandwidthPlaylistReps[bandwidthPlaylistReps.length - 1]; // get all of the renditions with the same (highest) bandwidth\n // and then taking the very first element\n\n const bandwidthBestRep = bandwidthPlaylistReps.filter(rep => rep.bandwidth === highestRemainingBandwidthRep.bandwidth)[0]; // if we're not going to limit renditions by player size, make an early decision.\n\n if (limitRenditionByPlayerDimensions === false) {\n const chosenRep = bandwidthBestRep || enabledPlaylistReps[0] || sortedPlaylistReps[0];\n\n if (chosenRep && chosenRep.playlist) {\n let type = 'sortedPlaylistReps';\n\n if (bandwidthBestRep) {\n type = 'bandwidthBestRep';\n }\n\n if (enabledPlaylistReps[0]) {\n type = 'enabledPlaylistReps';\n }\n\n logFn(`choosing ${representationToString(chosenRep)} using ${type} with options`, options);\n return chosenRep.playlist;\n }\n\n logFn('could not choose a playlist with options', options);\n return null;\n } // filter out playlists without resolution information\n\n\n const haveResolution = bandwidthPlaylistReps.filter(rep => rep.width && rep.height); // sort variants by resolution\n\n stableSort(haveResolution, (left, right) => left.width - right.width); // if we have the exact resolution as the player use it\n\n const resolutionBestRepList = haveResolution.filter(rep => rep.width === playerWidth && rep.height === playerHeight);\n highestRemainingBandwidthRep = resolutionBestRepList[resolutionBestRepList.length - 1]; // ensure that we pick the highest bandwidth variant that have exact resolution\n\n const resolutionBestRep = resolutionBestRepList.filter(rep => rep.bandwidth === highestRemainingBandwidthRep.bandwidth)[0];\n let resolutionPlusOneList;\n let resolutionPlusOneSmallest;\n let resolutionPlusOneRep; // find the smallest variant that is larger than the player\n // if there is no match of exact resolution\n\n if (!resolutionBestRep) {\n resolutionPlusOneList = haveResolution.filter(rep => rep.width > playerWidth || rep.height > playerHeight); // find all the variants have the same smallest resolution\n\n resolutionPlusOneSmallest = resolutionPlusOneList.filter(rep => rep.width === resolutionPlusOneList[0].width && rep.height === resolutionPlusOneList[0].height); // ensure that we also pick the highest bandwidth variant that\n // is just-larger-than the video player\n\n highestRemainingBandwidthRep = resolutionPlusOneSmallest[resolutionPlusOneSmallest.length - 1];\n resolutionPlusOneRep = resolutionPlusOneSmallest.filter(rep => rep.bandwidth === highestRemainingBandwidthRep.bandwidth)[0];\n }\n\n let leastPixelDiffRep; // If this selector proves to be better than others,\n // resolutionPlusOneRep and resolutionBestRep and all\n // the code involving them should be removed.\n\n if (playlistController.leastPixelDiffSelector) {\n // find the variant that is closest to the player's pixel size\n const leastPixelDiffList = haveResolution.map(rep => {\n rep.pixelDiff = Math.abs(rep.width - playerWidth) + Math.abs(rep.height - playerHeight);\n return rep;\n }); // get the highest bandwidth, closest resolution playlist\n\n stableSort(leastPixelDiffList, (left, right) => {\n // sort by highest bandwidth if pixelDiff is the same\n if (left.pixelDiff === right.pixelDiff) {\n return right.bandwidth - left.bandwidth;\n }\n\n return left.pixelDiff - right.pixelDiff;\n });\n leastPixelDiffRep = leastPixelDiffList[0];\n } // fallback chain of variants\n\n\n const chosenRep = leastPixelDiffRep || resolutionPlusOneRep || resolutionBestRep || bandwidthBestRep || enabledPlaylistReps[0] || sortedPlaylistReps[0];\n\n if (chosenRep && chosenRep.playlist) {\n let type = 'sortedPlaylistReps';\n\n if (leastPixelDiffRep) {\n type = 'leastPixelDiffRep';\n } else if (resolutionPlusOneRep) {\n type = 'resolutionPlusOneRep';\n } else if (resolutionBestRep) {\n type = 'resolutionBestRep';\n } else if (bandwidthBestRep) {\n type = 'bandwidthBestRep';\n } else if (enabledPlaylistReps[0]) {\n type = 'enabledPlaylistReps';\n }\n\n logFn(`choosing ${representationToString(chosenRep)} using ${type} with options`, options);\n return chosenRep.playlist;\n }\n\n logFn('could not choose a playlist with options', options);\n return null;\n};\n\n/**\n * Chooses the appropriate media playlist based on the most recent\n * bandwidth estimate and the player size.\n *\n * Expects to be called within the context of an instance of VhsHandler\n *\n * @return {Playlist} the highest bitrate playlist less than the\n * currently detected bandwidth, accounting for some amount of\n * bandwidth variance\n */\n\nconst lastBandwidthSelector = function () {\n let pixelRatio = this.useDevicePixelRatio ? window$1.devicePixelRatio || 1 : 1;\n\n if (!isNaN(this.customPixelRatio)) {\n pixelRatio = this.customPixelRatio;\n }\n\n return simpleSelector(this.playlists.main, this.systemBandwidth, parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10) * pixelRatio, parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10) * pixelRatio, this.limitRenditionByPlayerDimensions, this.playlistController_);\n};\n/**\n * Chooses the appropriate media playlist based on an\n * exponential-weighted moving average of the bandwidth after\n * filtering for player size.\n *\n * Expects to be called within the context of an instance of VhsHandler\n *\n * @param {number} decay - a number between 0 and 1. Higher values of\n * this parameter will cause previous bandwidth estimates to lose\n * significance more quickly.\n * @return {Function} a function which can be invoked to create a new\n * playlist selector function.\n * @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average\n */\n\nconst movingAverageBandwidthSelector = function (decay) {\n let average = -1;\n let lastSystemBandwidth = -1;\n\n if (decay < 0 || decay > 1) {\n throw new Error('Moving average bandwidth decay must be between 0 and 1.');\n }\n\n return function () {\n let pixelRatio = this.useDevicePixelRatio ? window$1.devicePixelRatio || 1 : 1;\n\n if (!isNaN(this.customPixelRatio)) {\n pixelRatio = this.customPixelRatio;\n }\n\n if (average < 0) {\n average = this.systemBandwidth;\n lastSystemBandwidth = this.systemBandwidth;\n } // stop the average value from decaying for every 250ms\n // when the systemBandwidth is constant\n // and\n // stop average from setting to a very low value when the\n // systemBandwidth becomes 0 in case of chunk cancellation\n\n\n if (this.systemBandwidth > 0 && this.systemBandwidth !== lastSystemBandwidth) {\n average = decay * this.systemBandwidth + (1 - decay) * average;\n lastSystemBandwidth = this.systemBandwidth;\n }\n\n return simpleSelector(this.playlists.main, average, parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10) * pixelRatio, parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10) * pixelRatio, this.limitRenditionByPlayerDimensions, this.playlistController_);\n };\n};\n/**\n * Chooses the appropriate media playlist based on the potential to rebuffer\n *\n * @param {Object} settings\n * Object of information required to use this selector\n * @param {Object} settings.main\n * Object representation of the main manifest\n * @param {number} settings.currentTime\n * The current time of the player\n * @param {number} settings.bandwidth\n * Current measured bandwidth\n * @param {number} settings.duration\n * Duration of the media\n * @param {number} settings.segmentDuration\n * Segment duration to be used in round trip time calculations\n * @param {number} settings.timeUntilRebuffer\n * Time left in seconds until the player has to rebuffer\n * @param {number} settings.currentTimeline\n * The current timeline segments are being loaded from\n * @param {SyncController} settings.syncController\n * SyncController for determining if we have a sync point for a given playlist\n * @return {Object|null}\n * {Object} return.playlist\n * The highest bandwidth playlist with the least amount of rebuffering\n * {Number} return.rebufferingImpact\n * The amount of time in seconds switching to this playlist will rebuffer. A\n * negative value means that switching will cause zero rebuffering.\n */\n\nconst minRebufferMaxBandwidthSelector = function (settings) {\n const {\n main,\n currentTime,\n bandwidth,\n duration,\n segmentDuration,\n timeUntilRebuffer,\n currentTimeline,\n syncController\n } = settings; // filter out any playlists that have been excluded due to\n // incompatible configurations\n\n const compatiblePlaylists = main.playlists.filter(playlist => !Playlist.isIncompatible(playlist)); // filter out any playlists that have been disabled manually through the representations\n // api or excluded temporarily due to playback errors.\n\n let enabledPlaylists = compatiblePlaylists.filter(Playlist.isEnabled);\n\n if (!enabledPlaylists.length) {\n // if there are no enabled playlists, then they have all been excluded or disabled\n // by the user through the representations api. In this case, ignore exclusion and\n // fallback to what the user wants by using playlists the user has not disabled.\n enabledPlaylists = compatiblePlaylists.filter(playlist => !Playlist.isDisabled(playlist));\n }\n\n const bandwidthPlaylists = enabledPlaylists.filter(Playlist.hasAttribute.bind(null, 'BANDWIDTH'));\n const rebufferingEstimates = bandwidthPlaylists.map(playlist => {\n const syncPoint = syncController.getSyncPoint(playlist, duration, currentTimeline, currentTime); // If there is no sync point for this playlist, switching to it will require a\n // sync request first. This will double the request time\n\n const numRequests = syncPoint ? 1 : 2;\n const requestTimeEstimate = Playlist.estimateSegmentRequestTime(segmentDuration, bandwidth, playlist);\n const rebufferingImpact = requestTimeEstimate * numRequests - timeUntilRebuffer;\n return {\n playlist,\n rebufferingImpact\n };\n });\n const noRebufferingPlaylists = rebufferingEstimates.filter(estimate => estimate.rebufferingImpact <= 0); // Sort by bandwidth DESC\n\n stableSort(noRebufferingPlaylists, (a, b) => comparePlaylistBandwidth(b.playlist, a.playlist));\n\n if (noRebufferingPlaylists.length) {\n return noRebufferingPlaylists[0];\n }\n\n stableSort(rebufferingEstimates, (a, b) => a.rebufferingImpact - b.rebufferingImpact);\n return rebufferingEstimates[0] || null;\n};\n/**\n * Chooses the appropriate media playlist, which in this case is the lowest bitrate\n * one with video. If no renditions with video exist, return the lowest audio rendition.\n *\n * Expects to be called within the context of an instance of VhsHandler\n *\n * @return {Object|null}\n * {Object} return.playlist\n * The lowest bitrate playlist that contains a video codec. If no such rendition\n * exists pick the lowest audio rendition.\n */\n\nconst lowestBitrateCompatibleVariantSelector = function () {\n // filter out any playlists that have been excluded due to\n // incompatible configurations or playback errors\n const playlists = this.playlists.main.playlists.filter(Playlist.isEnabled); // Sort ascending by bitrate\n\n stableSort(playlists, (a, b) => comparePlaylistBandwidth(a, b)); // Parse and assume that playlists with no video codec have no video\n // (this is not necessarily true, although it is generally true).\n //\n // If an entire manifest has no valid videos everything will get filtered\n // out.\n\n const playlistsWithVideo = playlists.filter(playlist => !!codecsForPlaylist(this.playlists.main, playlist).video);\n return playlistsWithVideo[0] || null;\n};\n\n/**\n * Combine all segments into a single Uint8Array\n *\n * @param {Object} segmentObj\n * @return {Uint8Array} concatenated bytes\n * @private\n */\nconst concatSegments = segmentObj => {\n let offset = 0;\n let tempBuffer;\n\n if (segmentObj.bytes) {\n tempBuffer = new Uint8Array(segmentObj.bytes); // combine the individual segments into one large typed-array\n\n segmentObj.segments.forEach(segment => {\n tempBuffer.set(segment, offset);\n offset += segment.byteLength;\n });\n }\n\n return tempBuffer;\n};\n/**\n * Example:\n * https://host.com/path1/path2/path3/segment.ts?arg1=val1\n * -->\n * path3/segment.ts\n *\n * @param resolvedUri\n * @return {string}\n */\n\nfunction compactSegmentUrlDescription(resolvedUri) {\n try {\n return new URL(resolvedUri).pathname.split('/').slice(-2).join('/');\n } catch (e) {\n return '';\n }\n}\n\n/**\n * @file text-tracks.js\n */\n/**\n * Create captions text tracks on video.js if they do not exist\n *\n * @param {Object} inbandTextTracks a reference to current inbandTextTracks\n * @param {Object} tech the video.js tech\n * @param {Object} captionStream the caption stream to create\n * @private\n */\n\nconst createCaptionsTrackIfNotExists = function (inbandTextTracks, tech, captionStream) {\n if (!inbandTextTracks[captionStream]) {\n tech.trigger({\n type: 'usage',\n name: 'vhs-608'\n });\n let instreamId = captionStream; // we need to translate SERVICEn for 708 to how mux.js currently labels them\n\n if (/^cc708_/.test(captionStream)) {\n instreamId = 'SERVICE' + captionStream.split('_')[1];\n }\n\n const track = tech.textTracks().getTrackById(instreamId);\n\n if (track) {\n // Resuse an existing track with a CC# id because this was\n // very likely created by videojs-contrib-hls from information\n // in the m3u8 for us to use\n inbandTextTracks[captionStream] = track;\n } else {\n // This section gets called when we have caption services that aren't specified in the manifest.\n // Manifest level caption services are handled in media-groups.js under CLOSED-CAPTIONS.\n const captionServices = tech.options_.vhs && tech.options_.vhs.captionServices || {};\n let label = captionStream;\n let language = captionStream;\n let def = false;\n const captionService = captionServices[instreamId];\n\n if (captionService) {\n label = captionService.label;\n language = captionService.language;\n def = captionService.default;\n } // Otherwise, create a track with the default `CC#` label and\n // without a language\n\n\n inbandTextTracks[captionStream] = tech.addRemoteTextTrack({\n kind: 'captions',\n id: instreamId,\n // TODO: investigate why this doesn't seem to turn the caption on by default\n default: def,\n label,\n language\n }, false).track;\n }\n }\n};\n/**\n * Add caption text track data to a source handler given an array of captions\n *\n * @param {Object}\n * @param {Object} inbandTextTracks the inband text tracks\n * @param {number} timestampOffset the timestamp offset of the source buffer\n * @param {Array} captionArray an array of caption data\n * @private\n */\n\nconst addCaptionData = function ({\n inbandTextTracks,\n captionArray,\n timestampOffset\n}) {\n if (!captionArray) {\n return;\n }\n\n const Cue = window$1.WebKitDataCue || window$1.VTTCue;\n captionArray.forEach(caption => {\n const track = caption.stream; // in CEA 608 captions, video.js/mux.js sends a content array\n // with positioning data\n\n if (caption.content) {\n caption.content.forEach(value => {\n const cue = new Cue(caption.startTime + timestampOffset, caption.endTime + timestampOffset, value.text);\n cue.line = value.line;\n cue.align = 'left';\n cue.position = value.position;\n cue.positionAlign = 'line-left';\n inbandTextTracks[track].addCue(cue);\n });\n } else {\n // otherwise, a text value with combined captions is sent\n inbandTextTracks[track].addCue(new Cue(caption.startTime + timestampOffset, caption.endTime + timestampOffset, caption.text));\n }\n });\n};\n/**\n * Define properties on a cue for backwards compatability,\n * but warn the user that the way that they are using it\n * is depricated and will be removed at a later date.\n *\n * @param {Cue} cue the cue to add the properties on\n * @private\n */\n\nconst deprecateOldCue = function (cue) {\n Object.defineProperties(cue.frame, {\n id: {\n get() {\n videojs.log.warn('cue.frame.id is deprecated. Use cue.value.key instead.');\n return cue.value.key;\n }\n\n },\n value: {\n get() {\n videojs.log.warn('cue.frame.value is deprecated. Use cue.value.data instead.');\n return cue.value.data;\n }\n\n },\n privateData: {\n get() {\n videojs.log.warn('cue.frame.privateData is deprecated. Use cue.value.data instead.');\n return cue.value.data;\n }\n\n }\n });\n};\n/**\n * Add metadata text track data to a source handler given an array of metadata\n *\n * @param {Object}\n * @param {Object} inbandTextTracks the inband text tracks\n * @param {Array} metadataArray an array of meta data\n * @param {number} timestampOffset the timestamp offset of the source buffer\n * @param {number} videoDuration the duration of the video\n * @private\n */\n\n\nconst addMetadata = ({\n inbandTextTracks,\n metadataArray,\n timestampOffset,\n videoDuration\n}) => {\n if (!metadataArray) {\n return;\n }\n\n const Cue = window$1.WebKitDataCue || window$1.VTTCue;\n const metadataTrack = inbandTextTracks.metadataTrack_;\n\n if (!metadataTrack) {\n return;\n }\n\n metadataArray.forEach(metadata => {\n const time = metadata.cueTime + timestampOffset; // if time isn't a finite number between 0 and Infinity, like NaN,\n // ignore this bit of metadata.\n // This likely occurs when you have an non-timed ID3 tag like TIT2,\n // which is the \"Title/Songname/Content description\" frame\n\n if (typeof time !== 'number' || window$1.isNaN(time) || time < 0 || !(time < Infinity)) {\n return;\n } // If we have no frames, we can't create a cue.\n\n\n if (!metadata.frames || !metadata.frames.length) {\n return;\n }\n\n metadata.frames.forEach(frame => {\n const cue = new Cue(time, time, frame.value || frame.url || frame.data || '');\n cue.frame = frame;\n cue.value = frame;\n deprecateOldCue(cue);\n metadataTrack.addCue(cue);\n });\n });\n\n if (!metadataTrack.cues || !metadataTrack.cues.length) {\n return;\n } // Updating the metadeta cues so that\n // the endTime of each cue is the startTime of the next cue\n // the endTime of last cue is the duration of the video\n\n\n const cues = metadataTrack.cues;\n const cuesArray = []; // Create a copy of the TextTrackCueList...\n // ...disregarding cues with a falsey value\n\n for (let i = 0; i < cues.length; i++) {\n if (cues[i]) {\n cuesArray.push(cues[i]);\n }\n } // Group cues by their startTime value\n\n\n const cuesGroupedByStartTime = cuesArray.reduce((obj, cue) => {\n const timeSlot = obj[cue.startTime] || [];\n timeSlot.push(cue);\n obj[cue.startTime] = timeSlot;\n return obj;\n }, {}); // Sort startTimes by ascending order\n\n const sortedStartTimes = Object.keys(cuesGroupedByStartTime).sort((a, b) => Number(a) - Number(b)); // Map each cue group's endTime to the next group's startTime\n\n sortedStartTimes.forEach((startTime, idx) => {\n const cueGroup = cuesGroupedByStartTime[startTime];\n const finiteDuration = isFinite(videoDuration) ? videoDuration : startTime;\n const nextTime = Number(sortedStartTimes[idx + 1]) || finiteDuration; // Map each cue's endTime the next group's startTime\n\n cueGroup.forEach(cue => {\n cue.endTime = nextTime;\n });\n });\n}; // object for mapping daterange attributes\n\nconst dateRangeAttr = {\n id: 'ID',\n class: 'CLASS',\n startDate: 'START-DATE',\n duration: 'DURATION',\n endDate: 'END-DATE',\n endOnNext: 'END-ON-NEXT',\n plannedDuration: 'PLANNED-DURATION',\n scte35Out: 'SCTE35-OUT',\n scte35In: 'SCTE35-IN'\n};\nconst dateRangeKeysToOmit = new Set(['id', 'class', 'startDate', 'duration', 'endDate', 'endOnNext', 'startTime', 'endTime', 'processDateRange']);\n/**\n * Add DateRange metadata text track to a source handler given an array of metadata\n *\n * @param {Object}\n * @param {Object} inbandTextTracks the inband text tracks\n * @param {Array} dateRanges parsed media playlist\n * @private\n */\n\nconst addDateRangeMetadata = ({\n inbandTextTracks,\n dateRanges\n}) => {\n const metadataTrack = inbandTextTracks.metadataTrack_;\n\n if (!metadataTrack) {\n return;\n }\n\n const Cue = window$1.WebKitDataCue || window$1.VTTCue;\n dateRanges.forEach(dateRange => {\n // we generate multiple cues for each date range with different attributes\n for (const key of Object.keys(dateRange)) {\n if (dateRangeKeysToOmit.has(key)) {\n continue;\n }\n\n const cue = new Cue(dateRange.startTime, dateRange.endTime, '');\n cue.id = dateRange.id;\n cue.type = 'com.apple.quicktime.HLS';\n cue.value = {\n key: dateRangeAttr[key],\n data: dateRange[key]\n };\n\n if (key === 'scte35Out' || key === 'scte35In') {\n cue.value.data = new Uint8Array(cue.value.data.match(/[\\da-f]{2}/gi)).buffer;\n }\n\n metadataTrack.addCue(cue);\n }\n\n dateRange.processDateRange();\n });\n};\n/**\n * Create metadata text track on video.js if it does not exist\n *\n * @param {Object} inbandTextTracks a reference to current inbandTextTracks\n * @param {string} dispatchType the inband metadata track dispatch type\n * @param {Object} tech the video.js tech\n * @private\n */\n\nconst createMetadataTrackIfNotExists = (inbandTextTracks, dispatchType, tech) => {\n if (inbandTextTracks.metadataTrack_) {\n return;\n }\n\n inbandTextTracks.metadataTrack_ = tech.addRemoteTextTrack({\n kind: 'metadata',\n label: 'Timed Metadata'\n }, false).track;\n\n if (!videojs.browser.IS_ANY_SAFARI) {\n inbandTextTracks.metadataTrack_.inBandMetadataTrackDispatchType = dispatchType;\n }\n};\n/**\n * Remove cues from a track on video.js.\n *\n * @param {Double} start start of where we should remove the cue\n * @param {Double} end end of where the we should remove the cue\n * @param {Object} track the text track to remove the cues from\n * @private\n */\n\nconst removeCuesFromTrack = function (start, end, track) {\n let i;\n let cue;\n\n if (!track) {\n return;\n }\n\n if (!track.cues) {\n return;\n }\n\n i = track.cues.length;\n\n while (i--) {\n cue = track.cues[i]; // Remove any cue within the provided start and end time\n\n if (cue.startTime >= start && cue.endTime <= end) {\n track.removeCue(cue);\n }\n }\n};\n/**\n * Remove duplicate cues from a track on video.js (a cue is considered a\n * duplicate if it has the same time interval and text as another)\n *\n * @param {Object} track the text track to remove the duplicate cues from\n * @private\n */\n\nconst removeDuplicateCuesFromTrack = function (track) {\n const cues = track.cues;\n\n if (!cues) {\n return;\n }\n\n const uniqueCues = {};\n\n for (let i = cues.length - 1; i >= 0; i--) {\n const cue = cues[i];\n const cueKey = `${cue.startTime}-${cue.endTime}-${cue.text}`;\n\n if (uniqueCues[cueKey]) {\n track.removeCue(cue);\n } else {\n uniqueCues[cueKey] = cue;\n }\n }\n};\n\n/**\n * Returns a list of gops in the buffer that have a pts value of 3 seconds or more in\n * front of current time.\n *\n * @param {Array} buffer\n * The current buffer of gop information\n * @param {number} currentTime\n * The current time\n * @param {Double} mapping\n * Offset to map display time to stream presentation time\n * @return {Array}\n * List of gops considered safe to append over\n */\n\nconst gopsSafeToAlignWith = (buffer, currentTime, mapping) => {\n if (typeof currentTime === 'undefined' || currentTime === null || !buffer.length) {\n return [];\n } // pts value for current time + 3 seconds to give a bit more wiggle room\n\n\n const currentTimePts = Math.ceil((currentTime - mapping + 3) * ONE_SECOND_IN_TS);\n let i;\n\n for (i = 0; i < buffer.length; i++) {\n if (buffer[i].pts > currentTimePts) {\n break;\n }\n }\n\n return buffer.slice(i);\n};\n/**\n * Appends gop information (timing and byteLength) received by the transmuxer for the\n * gops appended in the last call to appendBuffer\n *\n * @param {Array} buffer\n * The current buffer of gop information\n * @param {Array} gops\n * List of new gop information\n * @param {boolean} replace\n * If true, replace the buffer with the new gop information. If false, append the\n * new gop information to the buffer in the right location of time.\n * @return {Array}\n * Updated list of gop information\n */\n\nconst updateGopBuffer = (buffer, gops, replace) => {\n if (!gops.length) {\n return buffer;\n }\n\n if (replace) {\n // If we are in safe append mode, then completely overwrite the gop buffer\n // with the most recent appeneded data. This will make sure that when appending\n // future segments, we only try to align with gops that are both ahead of current\n // time and in the last segment appended.\n return gops.slice();\n }\n\n const start = gops[0].pts;\n let i = 0;\n\n for (i; i < buffer.length; i++) {\n if (buffer[i].pts >= start) {\n break;\n }\n }\n\n return buffer.slice(0, i).concat(gops);\n};\n/**\n * Removes gop information in buffer that overlaps with provided start and end\n *\n * @param {Array} buffer\n * The current buffer of gop information\n * @param {Double} start\n * position to start the remove at\n * @param {Double} end\n * position to end the remove at\n * @param {Double} mapping\n * Offset to map display time to stream presentation time\n */\n\nconst removeGopBuffer = (buffer, start, end, mapping) => {\n const startPts = Math.ceil((start - mapping) * ONE_SECOND_IN_TS);\n const endPts = Math.ceil((end - mapping) * ONE_SECOND_IN_TS);\n const updatedBuffer = buffer.slice();\n let i = buffer.length;\n\n while (i--) {\n if (buffer[i].pts <= endPts) {\n break;\n }\n }\n\n if (i === -1) {\n // no removal because end of remove range is before start of buffer\n return updatedBuffer;\n }\n\n let j = i + 1;\n\n while (j--) {\n if (buffer[j].pts <= startPts) {\n break;\n }\n } // clamp remove range start to 0 index\n\n\n j = Math.max(j, 0);\n updatedBuffer.splice(j, i - j + 1);\n return updatedBuffer;\n};\n\nconst shallowEqual = function (a, b) {\n // if both are undefined\n // or one or the other is undefined\n // they are not equal\n if (!a && !b || !a && b || a && !b) {\n return false;\n } // they are the same object and thus, equal\n\n\n if (a === b) {\n return true;\n } // sort keys so we can make sure they have\n // all the same keys later.\n\n\n const akeys = Object.keys(a).sort();\n const bkeys = Object.keys(b).sort(); // different number of keys, not equal\n\n if (akeys.length !== bkeys.length) {\n return false;\n }\n\n for (let i = 0; i < akeys.length; i++) {\n const key = akeys[i]; // different sorted keys, not equal\n\n if (key !== bkeys[i]) {\n return false;\n } // different values, not equal\n\n\n if (a[key] !== b[key]) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * The segment loader has no recourse except to fetch a segment in the\n * current playlist and use the internal timestamps in that segment to\n * generate a syncPoint. This function returns a good candidate index\n * for that process.\n *\n * @param {Array} segments - the segments array from a playlist.\n * @return {number} An index of a segment from the playlist to load\n */\n\nconst getSyncSegmentCandidate = function (currentTimeline, segments, targetTime) {\n segments = segments || [];\n const timelineSegments = [];\n let time = 0;\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n\n if (currentTimeline === segment.timeline) {\n timelineSegments.push(i);\n time += segment.duration;\n\n if (time > targetTime) {\n return i;\n }\n }\n }\n\n if (timelineSegments.length === 0) {\n return 0;\n } // default to the last timeline segment\n\n\n return timelineSegments[timelineSegments.length - 1];\n}; // In the event of a quota exceeded error, keep at least one second of back buffer. This\n// number was arbitrarily chosen and may be updated in the future, but seemed reasonable\n// as a start to prevent any potential issues with removing content too close to the\n// playhead.\n\nconst MIN_BACK_BUFFER = 1; // in ms\n\nconst CHECK_BUFFER_DELAY = 500;\n\nconst finite = num => typeof num === 'number' && isFinite(num); // With most content hovering around 30fps, if a segment has a duration less than a half\n// frame at 30fps or one frame at 60fps, the bandwidth and throughput calculations will\n// not accurately reflect the rest of the content.\n\n\nconst MIN_SEGMENT_DURATION_TO_SAVE_STATS = 1 / 60;\nconst illegalMediaSwitch = (loaderType, startingMedia, trackInfo) => {\n // Although these checks should most likely cover non 'main' types, for now it narrows\n // the scope of our checks.\n if (loaderType !== 'main' || !startingMedia || !trackInfo) {\n return null;\n }\n\n if (!trackInfo.hasAudio && !trackInfo.hasVideo) {\n return 'Neither audio nor video found in segment.';\n }\n\n if (startingMedia.hasVideo && !trackInfo.hasVideo) {\n return 'Only audio found in segment when we expected video.' + ' We can\\'t switch to audio only from a stream that had video.' + ' To get rid of this message, please add codec information to the manifest.';\n }\n\n if (!startingMedia.hasVideo && trackInfo.hasVideo) {\n return 'Video found in segment when we expected only audio.' + ' We can\\'t switch to a stream with video from an audio only stream.' + ' To get rid of this message, please add codec information to the manifest.';\n }\n\n return null;\n};\n/**\n * Calculates a time value that is safe to remove from the back buffer without interrupting\n * playback.\n *\n * @param {TimeRange} seekable\n * The current seekable range\n * @param {number} currentTime\n * The current time of the player\n * @param {number} targetDuration\n * The target duration of the current playlist\n * @return {number}\n * Time that is safe to remove from the back buffer without interrupting playback\n */\n\nconst safeBackBufferTrimTime = (seekable, currentTime, targetDuration) => {\n // 30 seconds before the playhead provides a safe default for trimming.\n //\n // Choosing a reasonable default is particularly important for high bitrate content and\n // VOD videos/live streams with large windows, as the buffer may end up overfilled and\n // throw an APPEND_BUFFER_ERR.\n let trimTime = currentTime - Config.BACK_BUFFER_LENGTH;\n\n if (seekable.length) {\n // Some live playlists may have a shorter window of content than the full allowed back\n // buffer. For these playlists, don't save content that's no longer within the window.\n trimTime = Math.max(trimTime, seekable.start(0));\n } // Don't remove within target duration of the current time to avoid the possibility of\n // removing the GOP currently being played, as removing it can cause playback stalls.\n\n\n const maxTrimTime = currentTime - targetDuration;\n return Math.min(maxTrimTime, trimTime);\n};\nconst segmentInfoString = segmentInfo => {\n const {\n startOfSegment,\n duration,\n segment,\n part,\n playlist: {\n mediaSequence: seq,\n id,\n segments = []\n },\n mediaIndex: index,\n partIndex,\n timeline\n } = segmentInfo;\n const segmentLen = segments.length - 1;\n let selection = 'mediaIndex/partIndex increment';\n\n if (segmentInfo.getMediaInfoForTime) {\n selection = `getMediaInfoForTime (${segmentInfo.getMediaInfoForTime})`;\n } else if (segmentInfo.isSyncRequest) {\n selection = 'getSyncSegmentCandidate (isSyncRequest)';\n }\n\n if (segmentInfo.independent) {\n selection += ` with independent ${segmentInfo.independent}`;\n }\n\n const hasPartIndex = typeof partIndex === 'number';\n const name = segmentInfo.segment.uri ? 'segment' : 'pre-segment';\n const zeroBasedPartCount = hasPartIndex ? getKnownPartCount({\n preloadSegment: segment\n }) - 1 : 0;\n return `${name} [${seq + index}/${seq + segmentLen}]` + (hasPartIndex ? ` part [${partIndex}/${zeroBasedPartCount}]` : '') + ` segment start/end [${segment.start} => ${segment.end}]` + (hasPartIndex ? ` part start/end [${part.start} => ${part.end}]` : '') + ` startOfSegment [${startOfSegment}]` + ` duration [${duration}]` + ` timeline [${timeline}]` + ` selected by [${selection}]` + ` playlist [${id}]`;\n};\n\nconst timingInfoPropertyForMedia = mediaType => `${mediaType}TimingInfo`;\n/**\n * Returns the timestamp offset to use for the segment.\n *\n * @param {number} segmentTimeline\n * The timeline of the segment\n * @param {number} currentTimeline\n * The timeline currently being followed by the loader\n * @param {number} startOfSegment\n * The estimated segment start\n * @param {TimeRange[]} buffered\n * The loader's buffer\n * @param {boolean} overrideCheck\n * If true, no checks are made to see if the timestamp offset value should be set,\n * but sets it directly to a value.\n *\n * @return {number|null}\n * Either a number representing a new timestamp offset, or null if the segment is\n * part of the same timeline\n */\n\n\nconst timestampOffsetForSegment = ({\n segmentTimeline,\n currentTimeline,\n startOfSegment,\n buffered,\n overrideCheck\n}) => {\n // Check to see if we are crossing a discontinuity to see if we need to set the\n // timestamp offset on the transmuxer and source buffer.\n //\n // Previously, we changed the timestampOffset if the start of this segment was less than\n // the currently set timestampOffset, but this isn't desirable as it can produce bad\n // behavior, especially around long running live streams.\n if (!overrideCheck && segmentTimeline === currentTimeline) {\n return null;\n } // When changing renditions, it's possible to request a segment on an older timeline. For\n // instance, given two renditions with the following:\n //\n // #EXTINF:10\n // segment1\n // #EXT-X-DISCONTINUITY\n // #EXTINF:10\n // segment2\n // #EXTINF:10\n // segment3\n //\n // And the current player state:\n //\n // current time: 8\n // buffer: 0 => 20\n //\n // The next segment on the current rendition would be segment3, filling the buffer from\n // 20s onwards. However, if a rendition switch happens after segment2 was requested,\n // then the next segment to be requested will be segment1 from the new rendition in\n // order to fill time 8 and onwards. Using the buffered end would result in repeated\n // content (since it would position segment1 of the new rendition starting at 20s). This\n // case can be identified when the new segment's timeline is a prior value. Instead of\n // using the buffered end, the startOfSegment can be used, which, hopefully, will be\n // more accurate to the actual start time of the segment.\n\n\n if (segmentTimeline < currentTimeline) {\n return startOfSegment;\n } // segmentInfo.startOfSegment used to be used as the timestamp offset, however, that\n // value uses the end of the last segment if it is available. While this value\n // should often be correct, it's better to rely on the buffered end, as the new\n // content post discontinuity should line up with the buffered end as if it were\n // time 0 for the new content.\n\n\n return buffered.length ? buffered.end(buffered.length - 1) : startOfSegment;\n};\n/**\n * Returns whether or not the loader should wait for a timeline change from the timeline\n * change controller before processing the segment.\n *\n * Primary timing in VHS goes by video. This is different from most media players, as\n * audio is more often used as the primary timing source. For the foreseeable future, VHS\n * will continue to use video as the primary timing source, due to the current logic and\n * expectations built around it.\n\n * Since the timing follows video, in order to maintain sync, the video loader is\n * responsible for setting both audio and video source buffer timestamp offsets.\n *\n * Setting different values for audio and video source buffers could lead to\n * desyncing. The following examples demonstrate some of the situations where this\n * distinction is important. Note that all of these cases involve demuxed content. When\n * content is muxed, the audio and video are packaged together, therefore syncing\n * separate media playlists is not an issue.\n *\n * CASE 1: Audio prepares to load a new timeline before video:\n *\n * Timeline: 0 1\n * Audio Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Audio Loader: ^\n * Video Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Video Loader ^\n *\n * In the above example, the audio loader is preparing to load the 6th segment, the first\n * after a discontinuity, while the video loader is still loading the 5th segment, before\n * the discontinuity.\n *\n * If the audio loader goes ahead and loads and appends the 6th segment before the video\n * loader crosses the discontinuity, then when appended, the 6th audio segment will use\n * the timestamp offset from timeline 0. This will likely lead to desyncing. In addition,\n * the audio loader must provide the audioAppendStart value to trim the content in the\n * transmuxer, and that value relies on the audio timestamp offset. Since the audio\n * timestamp offset is set by the video (main) loader, the audio loader shouldn't load the\n * segment until that value is provided.\n *\n * CASE 2: Video prepares to load a new timeline before audio:\n *\n * Timeline: 0 1\n * Audio Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Audio Loader: ^\n * Video Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Video Loader ^\n *\n * In the above example, the video loader is preparing to load the 6th segment, the first\n * after a discontinuity, while the audio loader is still loading the 5th segment, before\n * the discontinuity.\n *\n * If the video loader goes ahead and loads and appends the 6th segment, then once the\n * segment is loaded and processed, both the video and audio timestamp offsets will be\n * set, since video is used as the primary timing source. This is to ensure content lines\n * up appropriately, as any modifications to the video timing are reflected by audio when\n * the video loader sets the audio and video timestamp offsets to the same value. However,\n * setting the timestamp offset for audio before audio has had a chance to change\n * timelines will likely lead to desyncing, as the audio loader will append segment 5 with\n * a timestamp intended to apply to segments from timeline 1 rather than timeline 0.\n *\n * CASE 3: When seeking, audio prepares to load a new timeline before video\n *\n * Timeline: 0 1\n * Audio Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Audio Loader: ^\n * Video Segments: 0 1 2 3 4 5 DISCO 6 7 8 9\n * Video Loader ^\n *\n * In the above example, both audio and video loaders are loading segments from timeline\n * 0, but imagine that the seek originated from timeline 1.\n *\n * When seeking to a new timeline, the timestamp offset will be set based on the expected\n * segment start of the loaded video segment. In order to maintain sync, the audio loader\n * must wait for the video loader to load its segment and update both the audio and video\n * timestamp offsets before it may load and append its own segment. This is the case\n * whether the seek results in a mismatched segment request (e.g., the audio loader\n * chooses to load segment 3 and the video loader chooses to load segment 4) or the\n * loaders choose to load the same segment index from each playlist, as the segments may\n * not be aligned perfectly, even for matching segment indexes.\n *\n * @param {Object} timelinechangeController\n * @param {number} currentTimeline\n * The timeline currently being followed by the loader\n * @param {number} segmentTimeline\n * The timeline of the segment being loaded\n * @param {('main'|'audio')} loaderType\n * The loader type\n * @param {boolean} audioDisabled\n * Whether the audio is disabled for the loader. This should only be true when the\n * loader may have muxed audio in its segment, but should not append it, e.g., for\n * the main loader when an alternate audio playlist is active.\n *\n * @return {boolean}\n * Whether the loader should wait for a timeline change from the timeline change\n * controller before processing the segment\n */\n\nconst shouldWaitForTimelineChange = ({\n timelineChangeController,\n currentTimeline,\n segmentTimeline,\n loaderType,\n audioDisabled\n}) => {\n if (currentTimeline === segmentTimeline) {\n return false;\n }\n\n if (loaderType === 'audio') {\n const lastMainTimelineChange = timelineChangeController.lastTimelineChange({\n type: 'main'\n }); // Audio loader should wait if:\n //\n // * main hasn't had a timeline change yet (thus has not loaded its first segment)\n // * main hasn't yet changed to the timeline audio is looking to load\n\n return !lastMainTimelineChange || lastMainTimelineChange.to !== segmentTimeline;\n } // The main loader only needs to wait for timeline changes if there's demuxed audio.\n // Otherwise, there's nothing to wait for, since audio would be muxed into the main\n // loader's segments (or the content is audio/video only and handled by the main\n // loader).\n\n\n if (loaderType === 'main' && audioDisabled) {\n const pendingAudioTimelineChange = timelineChangeController.pendingTimelineChange({\n type: 'audio'\n }); // Main loader should wait for the audio loader if audio is not pending a timeline\n // change to the current timeline.\n //\n // Since the main loader is responsible for setting the timestamp offset for both\n // audio and video, the main loader must wait for audio to be about to change to its\n // timeline before setting the offset, otherwise, if audio is behind in loading,\n // segments from the previous timeline would be adjusted by the new timestamp offset.\n //\n // This requirement means that video will not cross a timeline until the audio is\n // about to cross to it, so that way audio and video will always cross the timeline\n // together.\n //\n // In addition to normal timeline changes, these rules also apply to the start of a\n // stream (going from a non-existent timeline, -1, to timeline 0). It's important\n // that these rules apply to the first timeline change because if they did not, it's\n // possible that the main loader will cross two timelines before the audio loader has\n // crossed one. Logic may be implemented to handle the startup as a special case, but\n // it's easier to simply treat all timeline changes the same.\n\n if (pendingAudioTimelineChange && pendingAudioTimelineChange.to === segmentTimeline) {\n return false;\n }\n\n return true;\n }\n\n return false;\n};\nconst shouldFixBadTimelineChanges = timelineChangeController => {\n if (!timelineChangeController) {\n return false;\n }\n\n const pendingAudioTimelineChange = timelineChangeController.pendingTimelineChange({\n type: 'audio'\n });\n const pendingMainTimelineChange = timelineChangeController.pendingTimelineChange({\n type: 'main'\n });\n const hasPendingTimelineChanges = pendingAudioTimelineChange && pendingMainTimelineChange;\n const differentPendingChanges = hasPendingTimelineChanges && pendingAudioTimelineChange.to !== pendingMainTimelineChange.to;\n const isNotInitialPendingTimelineChange = hasPendingTimelineChanges && pendingAudioTimelineChange.from !== -1 && pendingMainTimelineChange.from !== -1;\n\n if (isNotInitialPendingTimelineChange && differentPendingChanges) {\n return true;\n }\n\n return false;\n};\n/**\n * Check if the pending audio timeline change is behind the\n * pending main timeline change.\n *\n * @param {SegmentLoader} segmentLoader\n * @return {boolean}\n */\n\nconst isAudioTimelineBehind = segmentLoader => {\n const pendingAudioTimelineChange = segmentLoader.timelineChangeController_.pendingTimelineChange({\n type: 'audio'\n });\n const pendingMainTimelineChange = segmentLoader.timelineChangeController_.pendingTimelineChange({\n type: 'main'\n });\n const hasPendingTimelineChanges = pendingAudioTimelineChange && pendingMainTimelineChange;\n return hasPendingTimelineChanges && pendingAudioTimelineChange.to < pendingMainTimelineChange.to;\n};\n/**\n * A method to check if the player is waiting for a timeline change, and fixes\n * certain scenarios where the timelines need to be updated.\n *\n * @param {SegmentLoader} segmentLoader\n */\n\n\nconst checkAndFixTimelines = segmentLoader => {\n const segmentInfo = segmentLoader.pendingSegment_;\n\n if (!segmentInfo) {\n return;\n }\n\n const waitingForTimelineChange = shouldWaitForTimelineChange({\n timelineChangeController: segmentLoader.timelineChangeController_,\n currentTimeline: segmentLoader.currentTimeline_,\n segmentTimeline: segmentInfo.timeline,\n loaderType: segmentLoader.loaderType_,\n audioDisabled: segmentLoader.audioDisabled_\n });\n\n if (waitingForTimelineChange && shouldFixBadTimelineChanges(segmentLoader.timelineChangeController_)) {\n if (isAudioTimelineBehind(segmentLoader)) {\n segmentLoader.timelineChangeController_.trigger('audioTimelineBehind');\n return;\n }\n\n segmentLoader.timelineChangeController_.trigger('fixBadTimelineChange');\n }\n};\n\nconst mediaDuration = timingInfos => {\n let maxDuration = 0;\n ['video', 'audio'].forEach(function (type) {\n const typeTimingInfo = timingInfos[`${type}TimingInfo`];\n\n if (!typeTimingInfo) {\n return;\n }\n\n const {\n start,\n end\n } = typeTimingInfo;\n let duration;\n\n if (typeof start === 'bigint' || typeof end === 'bigint') {\n duration = window$1.BigInt(end) - window$1.BigInt(start);\n } else if (typeof start === 'number' && typeof end === 'number') {\n duration = end - start;\n }\n\n if (typeof duration !== 'undefined' && duration > maxDuration) {\n maxDuration = duration;\n }\n }); // convert back to a number if it is lower than MAX_SAFE_INTEGER\n // as we only need BigInt when we are above that.\n\n if (typeof maxDuration === 'bigint' && maxDuration < Number.MAX_SAFE_INTEGER) {\n maxDuration = Number(maxDuration);\n }\n\n return maxDuration;\n};\nconst segmentTooLong = ({\n segmentDuration,\n maxDuration\n}) => {\n // 0 duration segments are most likely due to metadata only segments or a lack of\n // information.\n if (!segmentDuration) {\n return false;\n } // For HLS:\n //\n // https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.3.1\n // The EXTINF duration of each Media Segment in the Playlist\n // file, when rounded to the nearest integer, MUST be less than or equal\n // to the target duration; longer segments can trigger playback stalls\n // or other errors.\n //\n // For DASH, the mpd-parser uses the largest reported segment duration as the target\n // duration. Although that reported duration is occasionally approximate (i.e., not\n // exact), a strict check may report that a segment is too long more often in DASH.\n\n\n return Math.round(segmentDuration) > maxDuration + TIME_FUDGE_FACTOR;\n};\nconst getTroublesomeSegmentDurationMessage = (segmentInfo, sourceType) => {\n // Right now we aren't following DASH's timing model exactly, so only perform\n // this check for HLS content.\n if (sourceType !== 'hls') {\n return null;\n }\n\n const segmentDuration = mediaDuration({\n audioTimingInfo: segmentInfo.audioTimingInfo,\n videoTimingInfo: segmentInfo.videoTimingInfo\n }); // Don't report if we lack information.\n //\n // If the segment has a duration of 0 it is either a lack of information or a\n // metadata only segment and shouldn't be reported here.\n\n if (!segmentDuration) {\n return null;\n }\n\n const targetDuration = segmentInfo.playlist.targetDuration;\n const isSegmentWayTooLong = segmentTooLong({\n segmentDuration,\n maxDuration: targetDuration * 2\n });\n const isSegmentSlightlyTooLong = segmentTooLong({\n segmentDuration,\n maxDuration: targetDuration\n });\n const segmentTooLongMessage = `Segment with index ${segmentInfo.mediaIndex} ` + `from playlist ${segmentInfo.playlist.id} ` + `has a duration of ${segmentDuration} ` + `when the reported duration is ${segmentInfo.duration} ` + `and the target duration is ${targetDuration}. ` + 'For HLS content, a duration in excess of the target duration may result in ' + 'playback issues. See the HLS specification section on EXT-X-TARGETDURATION for ' + 'more details: ' + 'https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.3.1';\n\n if (isSegmentWayTooLong || isSegmentSlightlyTooLong) {\n return {\n severity: isSegmentWayTooLong ? 'warn' : 'info',\n message: segmentTooLongMessage\n };\n }\n\n return null;\n};\n/**\n *\n * @param {Object} options type of segment loader and segment either segmentInfo or simple segment\n * @return a segmentInfo payload for events or errors.\n */\n\nconst segmentInfoPayload = ({\n type,\n segment\n}) => {\n if (!segment) {\n return;\n }\n\n const isEncrypted = Boolean(segment.key || segment.map && segment.map.ke);\n const isMediaInitialization = Boolean(segment.map && !segment.map.bytes);\n const start = segment.startOfSegment === undefined ? segment.start : segment.startOfSegment;\n return {\n type: type || segment.type,\n uri: segment.resolvedUri || segment.uri,\n start,\n duration: segment.duration,\n isEncrypted,\n isMediaInitialization\n };\n};\n/**\n * An object that manages segment loading and appending.\n *\n * @class SegmentLoader\n * @param {Object} options required and optional options\n * @extends videojs.EventTarget\n */\n\nclass SegmentLoader extends videojs.EventTarget {\n constructor(settings, options = {}) {\n super(); // check pre-conditions\n\n if (!settings) {\n throw new TypeError('Initialization settings are required');\n }\n\n if (typeof settings.currentTime !== 'function') {\n throw new TypeError('No currentTime getter specified');\n }\n\n if (!settings.mediaSource) {\n throw new TypeError('No MediaSource specified');\n } // public properties\n\n\n this.bandwidth = settings.bandwidth;\n this.throughput = {\n rate: 0,\n count: 0\n };\n this.roundTrip = NaN;\n this.resetStats_();\n this.mediaIndex = null;\n this.partIndex = null; // private settings\n\n this.hasPlayed_ = settings.hasPlayed;\n this.currentTime_ = settings.currentTime;\n this.seekable_ = settings.seekable;\n this.seeking_ = settings.seeking;\n this.duration_ = settings.duration;\n this.mediaSource_ = settings.mediaSource;\n this.vhs_ = settings.vhs;\n this.loaderType_ = settings.loaderType;\n this.currentMediaInfo_ = void 0;\n this.startingMediaInfo_ = void 0;\n this.segmentMetadataTrack_ = settings.segmentMetadataTrack;\n this.goalBufferLength_ = settings.goalBufferLength;\n this.sourceType_ = settings.sourceType;\n this.sourceUpdater_ = settings.sourceUpdater;\n this.inbandTextTracks_ = settings.inbandTextTracks;\n this.state_ = 'INIT';\n this.timelineChangeController_ = settings.timelineChangeController;\n this.shouldSaveSegmentTimingInfo_ = true;\n this.parse708captions_ = settings.parse708captions;\n this.useDtsForTimestampOffset_ = settings.useDtsForTimestampOffset;\n this.captionServices_ = settings.captionServices;\n this.exactManifestTimings = settings.exactManifestTimings;\n this.addMetadataToTextTrack = settings.addMetadataToTextTrack; // private instance variables\n\n this.checkBufferTimeout_ = null;\n this.error_ = void 0;\n this.currentTimeline_ = -1;\n this.shouldForceTimestampOffsetAfterResync_ = false;\n this.pendingSegment_ = null;\n this.xhrOptions_ = null;\n this.pendingSegments_ = [];\n this.audioDisabled_ = false;\n this.isPendingTimestampOffset_ = false; // TODO possibly move gopBuffer and timeMapping info to a separate controller\n\n this.gopBuffer_ = [];\n this.timeMapping_ = 0;\n this.safeAppend_ = false;\n this.appendInitSegment_ = {\n audio: true,\n video: true\n };\n this.playlistOfLastInitSegment_ = {\n audio: null,\n video: null\n };\n this.callQueue_ = []; // If the segment loader prepares to load a segment, but does not have enough\n // information yet to start the loading process (e.g., if the audio loader wants to\n // load a segment from the next timeline but the main loader hasn't yet crossed that\n // timeline), then the load call will be added to the queue until it is ready to be\n // processed.\n\n this.loadQueue_ = [];\n this.metadataQueue_ = {\n id3: [],\n caption: []\n };\n this.waitingOnRemove_ = false;\n this.quotaExceededErrorRetryTimeout_ = null; // Fragmented mp4 playback\n\n this.activeInitSegmentId_ = null;\n this.initSegments_ = {}; // HLSe playback\n\n this.cacheEncryptionKeys_ = settings.cacheEncryptionKeys;\n this.keyCache_ = {};\n this.decrypter_ = settings.decrypter; // Manages the tracking and generation of sync-points, mappings\n // between a time in the display time and a segment index within\n // a playlist\n\n this.syncController_ = settings.syncController;\n this.syncPoint_ = {\n segmentIndex: 0,\n time: 0\n };\n this.transmuxer_ = this.createTransmuxer_();\n\n this.triggerSyncInfoUpdate_ = () => this.trigger('syncinfoupdate');\n\n this.syncController_.on('syncinfoupdate', this.triggerSyncInfoUpdate_);\n this.mediaSource_.addEventListener('sourceopen', () => {\n if (!this.isEndOfStream_()) {\n this.ended_ = false;\n }\n }); // ...for determining the fetch location\n\n this.fetchAtBuffer_ = false;\n this.logger_ = logger(`SegmentLoader[${this.loaderType_}]`);\n Object.defineProperty(this, 'state', {\n get() {\n return this.state_;\n },\n\n set(newState) {\n if (newState !== this.state_) {\n this.logger_(`${this.state_} -> ${newState}`);\n this.state_ = newState;\n this.trigger('statechange');\n }\n }\n\n });\n this.sourceUpdater_.on('ready', () => {\n if (this.hasEnoughInfoToAppend_()) {\n this.processCallQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n });\n this.sourceUpdater_.on('codecschange', metadata => {\n this.trigger(_extends({\n type: 'codecschange'\n }, metadata));\n }); // Only the main loader needs to listen for pending timeline changes, as the main\n // loader should wait for audio to be ready to change its timeline so that both main\n // and audio timelines change together. For more details, see the\n // shouldWaitForTimelineChange function.\n\n if (this.loaderType_ === 'main') {\n this.timelineChangeController_.on('pendingtimelinechange', () => {\n if (this.hasEnoughInfoToAppend_()) {\n this.processCallQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n });\n } // The main loader only listens on pending timeline changes, but the audio loader,\n // since its loads follow main, needs to listen on timeline changes. For more details,\n // see the shouldWaitForTimelineChange function.\n\n\n if (this.loaderType_ === 'audio') {\n this.timelineChangeController_.on('timelinechange', metadata => {\n this.trigger(_extends({\n type: 'timelinechange'\n }, metadata));\n\n if (this.hasEnoughInfoToLoad_()) {\n this.processLoadQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n\n if (this.hasEnoughInfoToAppend_()) {\n this.processCallQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n });\n }\n }\n /**\n * TODO: Current sync controller consists of many hls-specific strategies\n * media sequence sync is also hls-specific, and we would like to be protocol-agnostic on this level\n * this should be a part of the sync-controller and sync controller should expect different strategy list based on the protocol.\n *\n * @return {MediaSequenceSync|null}\n * @private\n */\n\n\n get mediaSequenceSync_() {\n return this.syncController_.getMediaSequenceSync(this.loaderType_);\n }\n\n createTransmuxer_() {\n return segmentTransmuxer.createTransmuxer({\n remux: false,\n alignGopsAtEnd: this.safeAppend_,\n keepOriginalTimestamps: true,\n parse708captions: this.parse708captions_,\n captionServices: this.captionServices_\n });\n }\n /**\n * reset all of our media stats\n *\n * @private\n */\n\n\n resetStats_() {\n this.mediaBytesTransferred = 0;\n this.mediaRequests = 0;\n this.mediaRequestsAborted = 0;\n this.mediaRequestsTimedout = 0;\n this.mediaRequestsErrored = 0;\n this.mediaTransferDuration = 0;\n this.mediaSecondsLoaded = 0;\n this.mediaAppends = 0;\n }\n /**\n * dispose of the SegmentLoader and reset to the default state\n */\n\n\n dispose() {\n this.trigger('dispose');\n this.state = 'DISPOSED';\n this.pause();\n this.abort_();\n\n if (this.transmuxer_) {\n this.transmuxer_.terminate();\n }\n\n this.resetStats_();\n\n if (this.checkBufferTimeout_) {\n window$1.clearTimeout(this.checkBufferTimeout_);\n }\n\n if (this.syncController_ && this.triggerSyncInfoUpdate_) {\n this.syncController_.off('syncinfoupdate', this.triggerSyncInfoUpdate_);\n }\n\n this.off();\n }\n\n setAudio(enable) {\n this.audioDisabled_ = !enable;\n\n if (enable) {\n this.appendInitSegment_.audio = true;\n } else {\n // remove current track audio if it gets disabled\n this.sourceUpdater_.removeAudio(0, this.duration_());\n }\n }\n /**\n * abort anything that is currently doing on with the SegmentLoader\n * and reset to a default state\n */\n\n\n abort() {\n if (this.state !== 'WAITING') {\n if (this.pendingSegment_) {\n this.pendingSegment_ = null;\n }\n\n this.timelineChangeController_.clearPendingTimelineChange(this.loaderType_);\n return;\n }\n\n this.abort_(); // We aborted the requests we were waiting on, so reset the loader's state to READY\n // since we are no longer \"waiting\" on any requests. XHR callback is not always run\n // when the request is aborted. This will prevent the loader from being stuck in the\n // WAITING state indefinitely.\n\n this.state = 'READY'; // don't wait for buffer check timeouts to begin fetching the\n // next segment\n\n if (!this.paused()) {\n this.monitorBuffer_();\n }\n }\n /**\n * abort all pending xhr requests and null any pending segements\n *\n * @private\n */\n\n\n abort_() {\n if (this.pendingSegment_ && this.pendingSegment_.abortRequests) {\n this.pendingSegment_.abortRequests();\n } // clear out the segment being processed\n\n\n this.pendingSegment_ = null;\n this.callQueue_ = [];\n this.loadQueue_ = [];\n this.metadataQueue_.id3 = [];\n this.metadataQueue_.caption = [];\n this.timelineChangeController_.clearPendingTimelineChange(this.loaderType_);\n this.waitingOnRemove_ = false;\n window$1.clearTimeout(this.quotaExceededErrorRetryTimeout_);\n this.quotaExceededErrorRetryTimeout_ = null;\n }\n\n checkForAbort_(requestId) {\n // If the state is APPENDING, then aborts will not modify the state, meaning the first\n // callback that happens should reset the state to READY so that loading can continue.\n if (this.state === 'APPENDING' && !this.pendingSegment_) {\n this.state = 'READY';\n return true;\n }\n\n if (!this.pendingSegment_ || this.pendingSegment_.requestId !== requestId) {\n return true;\n }\n\n return false;\n }\n /**\n * set an error on the segment loader and null out any pending segements\n *\n * @param {Error} error the error to set on the SegmentLoader\n * @return {Error} the error that was set or that is currently set\n */\n\n\n error(error) {\n if (typeof error !== 'undefined') {\n this.logger_('error occurred:', error);\n this.error_ = error;\n }\n\n this.pendingSegment_ = null;\n return this.error_;\n }\n\n endOfStream() {\n this.ended_ = true;\n\n if (this.transmuxer_) {\n // need to clear out any cached data to prepare for the new segment\n segmentTransmuxer.reset(this.transmuxer_);\n }\n\n this.gopBuffer_.length = 0;\n this.pause();\n this.trigger('ended');\n }\n /**\n * Indicates which time ranges are buffered\n *\n * @return {TimeRange}\n * TimeRange object representing the current buffered ranges\n */\n\n\n buffered_() {\n const trackInfo = this.getMediaInfo_();\n\n if (!this.sourceUpdater_ || !trackInfo) {\n return createTimeRanges();\n }\n\n if (this.loaderType_ === 'main') {\n const {\n hasAudio,\n hasVideo,\n isMuxed\n } = trackInfo;\n\n if (hasVideo && hasAudio && !this.audioDisabled_ && !isMuxed) {\n return this.sourceUpdater_.buffered();\n }\n\n if (hasVideo) {\n return this.sourceUpdater_.videoBuffered();\n }\n } // One case that can be ignored for now is audio only with alt audio,\n // as we don't yet have proper support for that.\n\n\n return this.sourceUpdater_.audioBuffered();\n }\n /**\n * Gets and sets init segment for the provided map\n *\n * @param {Object} map\n * The map object representing the init segment to get or set\n * @param {boolean=} set\n * If true, the init segment for the provided map should be saved\n * @return {Object}\n * map object for desired init segment\n */\n\n\n initSegmentForMap(map, set = false) {\n if (!map) {\n return null;\n }\n\n const id = initSegmentId(map);\n let storedMap = this.initSegments_[id];\n\n if (set && !storedMap && map.bytes) {\n this.initSegments_[id] = storedMap = {\n resolvedUri: map.resolvedUri,\n byterange: map.byterange,\n bytes: map.bytes,\n tracks: map.tracks,\n timescales: map.timescales\n };\n }\n\n return storedMap || map;\n }\n /**\n * Gets and sets key for the provided key\n *\n * @param {Object} key\n * The key object representing the key to get or set\n * @param {boolean=} set\n * If true, the key for the provided key should be saved\n * @return {Object}\n * Key object for desired key\n */\n\n\n segmentKey(key, set = false) {\n if (!key) {\n return null;\n }\n\n const id = segmentKeyId(key);\n let storedKey = this.keyCache_[id]; // TODO: We should use the HTTP Expires header to invalidate our cache per\n // https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-6.2.3\n\n if (this.cacheEncryptionKeys_ && set && !storedKey && key.bytes) {\n this.keyCache_[id] = storedKey = {\n resolvedUri: key.resolvedUri,\n bytes: key.bytes\n };\n }\n\n const result = {\n resolvedUri: (storedKey || key).resolvedUri\n };\n\n if (storedKey) {\n result.bytes = storedKey.bytes;\n }\n\n return result;\n }\n /**\n * Returns true if all configuration required for loading is present, otherwise false.\n *\n * @return {boolean} True if the all configuration is ready for loading\n * @private\n */\n\n\n couldBeginLoading_() {\n return this.playlist_ && !this.paused();\n }\n /**\n * load a playlist and start to fill the buffer\n */\n\n\n load() {\n // un-pause\n this.monitorBuffer_(); // if we don't have a playlist yet, keep waiting for one to be\n // specified\n\n if (!this.playlist_) {\n return;\n } // if all the configuration is ready, initialize and begin loading\n\n\n if (this.state === 'INIT' && this.couldBeginLoading_()) {\n return this.init_();\n } // if we're in the middle of processing a segment already, don't\n // kick off an additional segment request\n\n\n if (!this.couldBeginLoading_() || this.state !== 'READY' && this.state !== 'INIT') {\n return;\n }\n\n this.state = 'READY';\n }\n /**\n * Once all the starting parameters have been specified, begin\n * operation. This method should only be invoked from the INIT\n * state.\n *\n * @private\n */\n\n\n init_() {\n this.state = 'READY'; // if this is the audio segment loader, and it hasn't been inited before, then any old\n // audio data from the muxed content should be removed\n\n this.resetEverything();\n return this.monitorBuffer_();\n }\n /**\n * set a playlist on the segment loader\n *\n * @param {PlaylistLoader} media the playlist to set on the segment loader\n */\n\n\n playlist(newPlaylist, options = {}) {\n if (!newPlaylist) {\n return;\n }\n\n if (this.playlist_ && this.playlist_.endList && newPlaylist.endList && this.playlist_.uri === newPlaylist.uri) {\n // skip update if both prev and new are vod and have the same URI\n return;\n }\n\n const oldPlaylist = this.playlist_;\n const segmentInfo = this.pendingSegment_;\n this.playlist_ = newPlaylist;\n this.xhrOptions_ = options; // when we haven't started playing yet, the start of a live playlist\n // is always our zero-time so force a sync update each time the playlist\n // is refreshed from the server\n //\n // Use the INIT state to determine if playback has started, as the playlist sync info\n // should be fixed once requests begin (as sync points are generated based on sync\n // info), but not before then.\n\n if (this.state === 'INIT') {\n newPlaylist.syncInfo = {\n mediaSequence: newPlaylist.mediaSequence,\n time: 0\n }; // Setting the date time mapping means mapping the program date time (if available)\n // to time 0 on the player's timeline. The playlist's syncInfo serves a similar\n // purpose, mapping the initial mediaSequence to time zero. Since the syncInfo can\n // be updated as the playlist is refreshed before the loader starts loading, the\n // program date time mapping needs to be updated as well.\n //\n // This mapping is only done for the main loader because a program date time should\n // map equivalently between playlists.\n\n if (this.loaderType_ === 'main') {\n this.syncController_.setDateTimeMappingForStart(newPlaylist);\n }\n }\n\n let oldId = null;\n\n if (oldPlaylist) {\n if (oldPlaylist.id) {\n oldId = oldPlaylist.id;\n } else if (oldPlaylist.uri) {\n oldId = oldPlaylist.uri;\n }\n }\n\n this.logger_(`playlist update [${oldId} => ${newPlaylist.id || newPlaylist.uri}]`);\n\n if (this.mediaSequenceSync_) {\n this.mediaSequenceSync_.update(newPlaylist, this.currentTime_());\n this.logger_(`Playlist update:\ncurrentTime: ${this.currentTime_()}\nbufferedEnd: ${lastBufferedEnd(this.buffered_())}\n`, this.mediaSequenceSync_.diagnostics);\n } // in VOD, this is always a rendition switch (or we updated our syncInfo above)\n // in LIVE, we always want to update with new playlists (including refreshes)\n\n\n this.trigger('syncinfoupdate'); // if we were unpaused but waiting for a playlist, start\n // buffering now\n\n if (this.state === 'INIT' && this.couldBeginLoading_()) {\n return this.init_();\n }\n\n if (!oldPlaylist || oldPlaylist.uri !== newPlaylist.uri) {\n if (this.mediaIndex !== null) {\n // we must reset/resync the segment loader when we switch renditions and\n // the segment loader is already synced to the previous rendition\n // We only want to reset the loader here for LLHLS playback, as resetLoader sets fetchAtBuffer_\n // to false, resulting in fetching segments at currentTime and causing repeated\n // same-segment requests on playlist change. This erroneously drives up the playback watcher\n // stalled segment count, as re-requesting segments at the currentTime or browser cached segments\n // will not change the buffer.\n // Reference for LLHLS fixes: https://github.com/videojs/http-streaming/pull/1201\n const isLLHLS = !newPlaylist.endList && typeof newPlaylist.partTargetDuration === 'number';\n\n if (isLLHLS) {\n this.resetLoader();\n } else {\n this.resyncLoader();\n }\n }\n\n this.currentMediaInfo_ = void 0;\n this.trigger('playlistupdate'); // the rest of this function depends on `oldPlaylist` being defined\n\n return;\n } // we reloaded the same playlist so we are in a live scenario\n // and we will likely need to adjust the mediaIndex\n\n\n const mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence;\n this.logger_(`live window shift [${mediaSequenceDiff}]`); // update the mediaIndex on the SegmentLoader\n // this is important because we can abort a request and this value must be\n // equal to the last appended mediaIndex\n\n if (this.mediaIndex !== null) {\n this.mediaIndex -= mediaSequenceDiff; // this can happen if we are going to load the first segment, but get a playlist\n // update during that. mediaIndex would go from 0 to -1 if mediaSequence in the\n // new playlist was incremented by 1.\n\n if (this.mediaIndex < 0) {\n this.mediaIndex = null;\n this.partIndex = null;\n } else {\n const segment = this.playlist_.segments[this.mediaIndex]; // partIndex should remain the same for the same segment\n // unless parts fell off of the playlist for this segment.\n // In that case we need to reset partIndex and resync\n\n if (this.partIndex && (!segment.parts || !segment.parts.length || !segment.parts[this.partIndex])) {\n const mediaIndex = this.mediaIndex;\n this.logger_(`currently processing part (index ${this.partIndex}) no longer exists.`);\n this.resetLoader(); // We want to throw away the partIndex and the data associated with it,\n // as the part was dropped from our current playlists segment.\n // The mediaIndex will still be valid so keep that around.\n\n this.mediaIndex = mediaIndex;\n }\n }\n } // update the mediaIndex on the SegmentInfo object\n // this is important because we will update this.mediaIndex with this value\n // in `handleAppendsDone_` after the segment has been successfully appended\n\n\n if (segmentInfo) {\n segmentInfo.mediaIndex -= mediaSequenceDiff;\n\n if (segmentInfo.mediaIndex < 0) {\n segmentInfo.mediaIndex = null;\n segmentInfo.partIndex = null;\n } else {\n // we need to update the referenced segment so that timing information is\n // saved for the new playlist's segment, however, if the segment fell off the\n // playlist, we can leave the old reference and just lose the timing info\n if (segmentInfo.mediaIndex >= 0) {\n segmentInfo.segment = newPlaylist.segments[segmentInfo.mediaIndex];\n }\n\n if (segmentInfo.partIndex >= 0 && segmentInfo.segment.parts) {\n segmentInfo.part = segmentInfo.segment.parts[segmentInfo.partIndex];\n }\n }\n }\n\n this.syncController_.saveExpiredSegmentInfo(oldPlaylist, newPlaylist);\n }\n /**\n * Prevent the loader from fetching additional segments. If there\n * is a segment request outstanding, it will finish processing\n * before the loader halts. A segment loader can be unpaused by\n * calling load().\n */\n\n\n pause() {\n if (this.checkBufferTimeout_) {\n window$1.clearTimeout(this.checkBufferTimeout_);\n this.checkBufferTimeout_ = null;\n }\n }\n /**\n * Returns whether the segment loader is fetching additional\n * segments when given the opportunity. This property can be\n * modified through calls to pause() and load().\n */\n\n\n paused() {\n return this.checkBufferTimeout_ === null;\n }\n /**\n * Delete all the buffered data and reset the SegmentLoader\n *\n * @param {Function} [done] an optional callback to be executed when the remove\n * operation is complete\n */\n\n\n resetEverything(done) {\n this.ended_ = false;\n this.activeInitSegmentId_ = null;\n this.appendInitSegment_ = {\n audio: true,\n video: true\n };\n this.resetLoader(); // remove from 0, the earliest point, to Infinity, to signify removal of everything.\n // VTT Segment Loader doesn't need to do anything but in the regular SegmentLoader,\n // we then clamp the value to duration if necessary.\n\n this.remove(0, Infinity, done); // clears fmp4 captions\n\n if (this.transmuxer_) {\n this.transmuxer_.postMessage({\n action: 'clearAllMp4Captions'\n }); // reset the cache in the transmuxer\n\n this.transmuxer_.postMessage({\n action: 'reset'\n });\n }\n }\n /**\n * Force the SegmentLoader to resync and start loading around the currentTime instead\n * of starting at the end of the buffer\n *\n * Useful for fast quality changes\n */\n\n\n resetLoader() {\n this.fetchAtBuffer_ = false;\n\n if (this.mediaSequenceSync_) {\n this.mediaSequenceSync_.resetAppendedStatus();\n }\n\n this.resyncLoader();\n }\n /**\n * Force the SegmentLoader to restart synchronization and make a conservative guess\n * before returning to the simple walk-forward method\n */\n\n\n resyncLoader() {\n if (this.transmuxer_) {\n // need to clear out any cached data to prepare for the new segment\n segmentTransmuxer.reset(this.transmuxer_);\n }\n\n this.mediaIndex = null;\n this.partIndex = null;\n this.syncPoint_ = null;\n this.isPendingTimestampOffset_ = false; // this is mainly to sync timing-info when switching between renditions with and without timestamp-rollover,\n // so we don't want it for DASH or fragmented mp4 segments.\n\n const isFmp4 = this.currentMediaInfo_ && this.currentMediaInfo_.isFmp4;\n const isHlsTs = this.sourceType_ === 'hls' && !isFmp4;\n\n if (isHlsTs) {\n this.shouldForceTimestampOffsetAfterResync_ = true;\n }\n\n this.callQueue_ = [];\n this.loadQueue_ = [];\n this.metadataQueue_.id3 = [];\n this.metadataQueue_.caption = [];\n this.abort();\n\n if (this.transmuxer_) {\n this.transmuxer_.postMessage({\n action: 'clearParsedMp4Captions'\n });\n }\n }\n /**\n * Remove any data in the source buffer between start and end times\n *\n * @param {number} start - the start time of the region to remove from the buffer\n * @param {number} end - the end time of the region to remove from the buffer\n * @param {Function} [done] - an optional callback to be executed when the remove\n * @param {boolean} force - force all remove operations to happen\n * operation is complete\n */\n\n\n remove(start, end, done = () => {}, force = false) {\n // clamp end to duration if we need to remove everything.\n // This is due to a browser bug that causes issues if we remove to Infinity.\n // videojs/videojs-contrib-hls#1225\n if (end === Infinity) {\n end = this.duration_();\n } // skip removes that would throw an error\n // commonly happens during a rendition switch at the start of a video\n // from start 0 to end 0\n\n\n if (end <= start) {\n this.logger_('skipping remove because end ${end} is <= start ${start}');\n return;\n }\n\n if (!this.sourceUpdater_ || !this.getMediaInfo_()) {\n this.logger_('skipping remove because no source updater or starting media info'); // nothing to remove if we haven't processed any media\n\n return;\n } // set it to one to complete this function's removes\n\n\n let removesRemaining = 1;\n\n const removeFinished = () => {\n removesRemaining--;\n\n if (removesRemaining === 0) {\n done();\n }\n };\n\n if (force || !this.audioDisabled_) {\n removesRemaining++;\n this.sourceUpdater_.removeAudio(start, end, removeFinished);\n } // While it would be better to only remove video if the main loader has video, this\n // should be safe with audio only as removeVideo will call back even if there's no\n // video buffer.\n //\n // In theory we can check to see if there's video before calling the remove, but in\n // the event that we're switching between renditions and from video to audio only\n // (when we add support for that), we may need to clear the video contents despite\n // what the new media will contain.\n\n\n if (force || this.loaderType_ === 'main') {\n this.gopBuffer_ = removeGopBuffer(this.gopBuffer_, start, end, this.timeMapping_);\n removesRemaining++;\n this.sourceUpdater_.removeVideo(start, end, removeFinished);\n } // remove any captions and ID3 tags\n\n\n for (const track in this.inbandTextTracks_) {\n removeCuesFromTrack(start, end, this.inbandTextTracks_[track]);\n }\n\n removeCuesFromTrack(start, end, this.segmentMetadataTrack_); // finished this function's removes\n\n removeFinished();\n }\n /**\n * (re-)schedule monitorBufferTick_ to run as soon as possible\n *\n * @private\n */\n\n\n monitorBuffer_() {\n if (this.checkBufferTimeout_) {\n window$1.clearTimeout(this.checkBufferTimeout_);\n }\n\n this.checkBufferTimeout_ = window$1.setTimeout(this.monitorBufferTick_.bind(this), 1);\n }\n /**\n * As long as the SegmentLoader is in the READY state, periodically\n * invoke fillBuffer_().\n *\n * @private\n */\n\n\n monitorBufferTick_() {\n if (this.state === 'READY') {\n this.fillBuffer_();\n }\n\n if (this.checkBufferTimeout_) {\n window$1.clearTimeout(this.checkBufferTimeout_);\n }\n\n this.checkBufferTimeout_ = window$1.setTimeout(this.monitorBufferTick_.bind(this), CHECK_BUFFER_DELAY);\n }\n /**\n * fill the buffer with segements unless the sourceBuffers are\n * currently updating\n *\n * Note: this function should only ever be called by monitorBuffer_\n * and never directly\n *\n * @private\n */\n\n\n fillBuffer_() {\n // TODO since the source buffer maintains a queue, and we shouldn't call this function\n // except when we're ready for the next segment, this check can most likely be removed\n if (this.sourceUpdater_.updating()) {\n return;\n } // see if we need to begin loading immediately\n\n\n const segmentInfo = this.chooseNextRequest_();\n\n if (!segmentInfo) {\n return;\n }\n\n const metadata = {\n segmentInfo: segmentInfoPayload({\n type: this.loaderType_,\n segment: segmentInfo\n })\n };\n this.trigger({\n type: 'segmentselected',\n metadata\n });\n\n if (typeof segmentInfo.timestampOffset === 'number') {\n this.isPendingTimestampOffset_ = false;\n this.timelineChangeController_.pendingTimelineChange({\n type: this.loaderType_,\n from: this.currentTimeline_,\n to: segmentInfo.timeline\n });\n }\n\n this.loadSegment_(segmentInfo);\n }\n /**\n * Determines if we should call endOfStream on the media source based\n * on the state of the buffer or if appened segment was the final\n * segment in the playlist.\n *\n * @param {number} [mediaIndex] the media index of segment we last appended\n * @param {Object} [playlist] a media playlist object\n * @return {boolean} do we need to call endOfStream on the MediaSource\n */\n\n\n isEndOfStream_(mediaIndex = this.mediaIndex, playlist = this.playlist_, partIndex = this.partIndex) {\n if (!playlist || !this.mediaSource_) {\n return false;\n }\n\n const segment = typeof mediaIndex === 'number' && playlist.segments[mediaIndex]; // mediaIndex is zero based but length is 1 based\n\n const appendedLastSegment = mediaIndex + 1 === playlist.segments.length; // true if there are no parts, or this is the last part.\n\n const appendedLastPart = !segment || !segment.parts || partIndex + 1 === segment.parts.length; // if we've buffered to the end of the video, we need to call endOfStream\n // so that MediaSources can trigger the `ended` event when it runs out of\n // buffered data instead of waiting for me\n\n return playlist.endList && this.mediaSource_.readyState === 'open' && appendedLastSegment && appendedLastPart;\n }\n /**\n * Determines what request should be made given current segment loader state.\n *\n * @return {Object} a request object that describes the segment/part to load\n */\n\n\n chooseNextRequest_() {\n const buffered = this.buffered_();\n const bufferedEnd = lastBufferedEnd(buffered) || 0;\n const bufferedTime = timeAheadOf(buffered, this.currentTime_());\n const preloaded = !this.hasPlayed_() && bufferedTime >= 1;\n const haveEnoughBuffer = bufferedTime >= this.goalBufferLength_();\n const segments = this.playlist_.segments; // return no segment if:\n // 1. we don't have segments\n // 2. The video has not yet played and we already downloaded a segment\n // 3. we already have enough buffered time\n\n if (!segments.length || preloaded || haveEnoughBuffer) {\n return null;\n }\n\n this.syncPoint_ = this.syncPoint_ || this.syncController_.getSyncPoint(this.playlist_, this.duration_(), this.currentTimeline_, this.currentTime_(), this.loaderType_);\n const next = {\n partIndex: null,\n mediaIndex: null,\n startOfSegment: null,\n playlist: this.playlist_,\n isSyncRequest: Boolean(!this.syncPoint_)\n };\n\n if (next.isSyncRequest) {\n next.mediaIndex = getSyncSegmentCandidate(this.currentTimeline_, segments, bufferedEnd);\n this.logger_(`choose next request. Can not find sync point. Fallback to media Index: ${next.mediaIndex}`);\n } else if (this.mediaIndex !== null) {\n const segment = segments[this.mediaIndex];\n const partIndex = typeof this.partIndex === 'number' ? this.partIndex : -1;\n next.startOfSegment = segment.end ? segment.end : bufferedEnd;\n\n if (segment.parts && segment.parts[partIndex + 1]) {\n next.mediaIndex = this.mediaIndex;\n next.partIndex = partIndex + 1;\n } else {\n next.mediaIndex = this.mediaIndex + 1;\n }\n } else {\n let segmentIndex;\n let partIndex;\n let startTime;\n const targetTime = this.fetchAtBuffer_ ? bufferedEnd : this.currentTime_();\n\n if (this.mediaSequenceSync_) {\n this.logger_(`chooseNextRequest_ request after Quality Switch:\nFor TargetTime: ${targetTime}.\nCurrentTime: ${this.currentTime_()}\nBufferedEnd: ${bufferedEnd}\nFetch At Buffer: ${this.fetchAtBuffer_}\n`, this.mediaSequenceSync_.diagnostics);\n }\n\n if (this.mediaSequenceSync_ && this.mediaSequenceSync_.isReliable) {\n const syncInfo = this.getSyncInfoFromMediaSequenceSync_(targetTime);\n\n if (!syncInfo) {\n const message = 'No sync info found while using media sequence sync';\n this.error({\n message,\n metadata: {\n errorType: videojs.Error.StreamingFailedToSelectNextSegment,\n error: new Error(message)\n }\n });\n this.logger_('chooseNextRequest_ - no sync info found using media sequence sync'); // no match\n\n return null;\n }\n\n this.logger_(`chooseNextRequest_ mediaSequence syncInfo (${syncInfo.start} --> ${syncInfo.end})`);\n segmentIndex = syncInfo.segmentIndex;\n partIndex = syncInfo.partIndex;\n startTime = syncInfo.start;\n } else {\n this.logger_('chooseNextRequest_ - fallback to a regular segment selection algorithm, based on a syncPoint.'); // fallback\n\n const mediaInfoForTime = Playlist.getMediaInfoForTime({\n exactManifestTimings: this.exactManifestTimings,\n playlist: this.playlist_,\n currentTime: targetTime,\n startingPartIndex: this.syncPoint_.partIndex,\n startingSegmentIndex: this.syncPoint_.segmentIndex,\n startTime: this.syncPoint_.time\n });\n segmentIndex = mediaInfoForTime.segmentIndex;\n partIndex = mediaInfoForTime.partIndex;\n startTime = mediaInfoForTime.startTime;\n }\n\n next.getMediaInfoForTime = this.fetchAtBuffer_ ? `bufferedEnd ${targetTime}` : `currentTime ${targetTime}`;\n next.mediaIndex = segmentIndex;\n next.startOfSegment = startTime;\n next.partIndex = partIndex;\n this.logger_(`choose next request. Playlist switched and we have a sync point. Media Index: ${next.mediaIndex} `);\n }\n\n const nextSegment = segments[next.mediaIndex];\n let nextPart = nextSegment && typeof next.partIndex === 'number' && nextSegment.parts && nextSegment.parts[next.partIndex]; // if the next segment index is invalid or\n // the next partIndex is invalid do not choose a next segment.\n\n if (!nextSegment || typeof next.partIndex === 'number' && !nextPart) {\n return null;\n } // if the next segment has parts, and we don't have a partIndex.\n // Set partIndex to 0\n\n\n if (typeof next.partIndex !== 'number' && nextSegment.parts) {\n next.partIndex = 0;\n nextPart = nextSegment.parts[0];\n } // independentSegments applies to every segment in a playlist. If independentSegments appears in a main playlist,\n // it applies to each segment in each media playlist.\n // https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming-23#section-4.3.5.1\n\n\n const hasIndependentSegments = this.vhs_.playlists && this.vhs_.playlists.main && this.vhs_.playlists.main.independentSegments || this.playlist_.independentSegments; // if we have no buffered data then we need to make sure\n // that the next part we append is \"independent\" if possible.\n // So we check if the previous part is independent, and request\n // it if it is.\n\n if (!bufferedTime && nextPart && !hasIndependentSegments && !nextPart.independent) {\n if (next.partIndex === 0) {\n const lastSegment = segments[next.mediaIndex - 1];\n const lastSegmentLastPart = lastSegment.parts && lastSegment.parts.length && lastSegment.parts[lastSegment.parts.length - 1];\n\n if (lastSegmentLastPart && lastSegmentLastPart.independent) {\n next.mediaIndex -= 1;\n next.partIndex = lastSegment.parts.length - 1;\n next.independent = 'previous segment';\n }\n } else if (nextSegment.parts[next.partIndex - 1].independent) {\n next.partIndex -= 1;\n next.independent = 'previous part';\n }\n }\n\n const ended = this.mediaSource_ && this.mediaSource_.readyState === 'ended'; // do not choose a next segment if all of the following:\n // 1. this is the last segment in the playlist\n // 2. end of stream has been called on the media source already\n // 3. the player is not seeking\n\n if (next.mediaIndex >= segments.length - 1 && ended && !this.seeking_()) {\n return null;\n }\n\n if (this.shouldForceTimestampOffsetAfterResync_) {\n this.shouldForceTimestampOffsetAfterResync_ = false;\n next.forceTimestampOffset = true;\n this.logger_('choose next request. Force timestamp offset after loader resync');\n }\n\n return this.generateSegmentInfo_(next);\n }\n\n getSyncInfoFromMediaSequenceSync_(targetTime) {\n if (!this.mediaSequenceSync_) {\n return null;\n } // we should pull the target time to the least available time if we drop out of sync for any reason\n\n\n const finalTargetTime = Math.max(targetTime, this.mediaSequenceSync_.start);\n\n if (targetTime !== finalTargetTime) {\n this.logger_(`getSyncInfoFromMediaSequenceSync_. Pulled target time from ${targetTime} to ${finalTargetTime}`);\n }\n\n const mediaSequenceSyncInfo = this.mediaSequenceSync_.getSyncInfoForTime(finalTargetTime);\n\n if (!mediaSequenceSyncInfo) {\n // no match at all\n return null;\n }\n\n if (!mediaSequenceSyncInfo.isAppended) {\n // has a perfect match\n return mediaSequenceSyncInfo;\n } // has match, but segment was already appended.\n // attempt to auto-advance to the nearest next segment:\n\n\n const nextMediaSequenceSyncInfo = this.mediaSequenceSync_.getSyncInfoForTime(mediaSequenceSyncInfo.end);\n\n if (!nextMediaSequenceSyncInfo) {\n // no match at all\n return null;\n }\n\n if (nextMediaSequenceSyncInfo.isAppended) {\n this.logger_('getSyncInfoFromMediaSequenceSync_: We encounter unexpected scenario where next media sequence sync info is also appended!');\n } // got match with the nearest next segment\n\n\n return nextMediaSequenceSyncInfo;\n }\n\n generateSegmentInfo_(options) {\n const {\n independent,\n playlist,\n mediaIndex,\n startOfSegment,\n isSyncRequest,\n partIndex,\n forceTimestampOffset,\n getMediaInfoForTime\n } = options;\n const segment = playlist.segments[mediaIndex];\n const part = typeof partIndex === 'number' && segment.parts[partIndex];\n const segmentInfo = {\n requestId: 'segment-loader-' + Math.random(),\n // resolve the segment URL relative to the playlist\n uri: part && part.resolvedUri || segment.resolvedUri,\n // the segment's mediaIndex at the time it was requested\n mediaIndex,\n partIndex: part ? partIndex : null,\n // whether or not to update the SegmentLoader's state with this\n // segment's mediaIndex\n isSyncRequest,\n startOfSegment,\n // the segment's playlist\n playlist,\n // unencrypted bytes of the segment\n bytes: null,\n // when a key is defined for this segment, the encrypted bytes\n encryptedBytes: null,\n // The target timestampOffset for this segment when we append it\n // to the source buffer\n timestampOffset: null,\n // The timeline that the segment is in\n timeline: segment.timeline,\n // The expected duration of the segment in seconds\n duration: part && part.duration || segment.duration,\n // retain the segment in case the playlist updates while doing an async process\n segment,\n part,\n byteLength: 0,\n transmuxer: this.transmuxer_,\n // type of getMediaInfoForTime that was used to get this segment\n getMediaInfoForTime,\n independent\n };\n const overrideCheck = typeof forceTimestampOffset !== 'undefined' ? forceTimestampOffset : this.isPendingTimestampOffset_;\n segmentInfo.timestampOffset = this.timestampOffsetForSegment_({\n segmentTimeline: segment.timeline,\n currentTimeline: this.currentTimeline_,\n startOfSegment,\n buffered: this.buffered_(),\n overrideCheck\n });\n const audioBufferedEnd = lastBufferedEnd(this.sourceUpdater_.audioBuffered());\n\n if (typeof audioBufferedEnd === 'number') {\n // since the transmuxer is using the actual timing values, but the buffer is\n // adjusted by the timestamp offset, we must adjust the value here\n segmentInfo.audioAppendStart = audioBufferedEnd - this.sourceUpdater_.audioTimestampOffset();\n }\n\n if (this.sourceUpdater_.videoBuffered().length) {\n segmentInfo.gopsToAlignWith = gopsSafeToAlignWith(this.gopBuffer_, // since the transmuxer is using the actual timing values, but the time is\n // adjusted by the timestmap offset, we must adjust the value here\n this.currentTime_() - this.sourceUpdater_.videoTimestampOffset(), this.timeMapping_);\n }\n\n return segmentInfo;\n } // get the timestampoffset for a segment,\n // added so that vtt segment loader can override and prevent\n // adding timestamp offsets.\n\n\n timestampOffsetForSegment_(options) {\n return timestampOffsetForSegment(options);\n }\n /**\n * Determines if the network has enough bandwidth to complete the current segment\n * request in a timely manner. If not, the request will be aborted early and bandwidth\n * updated to trigger a playlist switch.\n *\n * @param {Object} stats\n * Object containing stats about the request timing and size\n * @private\n */\n\n\n earlyAbortWhenNeeded_(stats) {\n if (this.vhs_.tech_.paused() || // Don't abort if the current playlist is on the lowestEnabledRendition\n // TODO: Replace using timeout with a boolean indicating whether this playlist is\n // the lowestEnabledRendition.\n !this.xhrOptions_.timeout || // Don't abort if we have no bandwidth information to estimate segment sizes\n !this.playlist_.attributes.BANDWIDTH) {\n return;\n } // Wait at least 1 second since the first byte of data has been received before\n // using the calculated bandwidth from the progress event to allow the bitrate\n // to stabilize\n\n\n if (Date.now() - (stats.firstBytesReceivedAt || Date.now()) < 1000) {\n return;\n }\n\n const currentTime = this.currentTime_();\n const measuredBandwidth = stats.bandwidth;\n const segmentDuration = this.pendingSegment_.duration;\n const requestTimeRemaining = Playlist.estimateSegmentRequestTime(segmentDuration, measuredBandwidth, this.playlist_, stats.bytesReceived); // Subtract 1 from the timeUntilRebuffer so we still consider an early abort\n // if we are only left with less than 1 second when the request completes.\n // A negative timeUntilRebuffering indicates we are already rebuffering\n\n const timeUntilRebuffer$1 = timeUntilRebuffer(this.buffered_(), currentTime, this.vhs_.tech_.playbackRate()) - 1; // Only consider aborting early if the estimated time to finish the download\n // is larger than the estimated time until the player runs out of forward buffer\n\n if (requestTimeRemaining <= timeUntilRebuffer$1) {\n return;\n }\n\n const switchCandidate = minRebufferMaxBandwidthSelector({\n main: this.vhs_.playlists.main,\n currentTime,\n bandwidth: measuredBandwidth,\n duration: this.duration_(),\n segmentDuration,\n timeUntilRebuffer: timeUntilRebuffer$1,\n currentTimeline: this.currentTimeline_,\n syncController: this.syncController_\n });\n\n if (!switchCandidate) {\n return;\n }\n\n const rebufferingImpact = requestTimeRemaining - timeUntilRebuffer$1;\n const timeSavedBySwitching = rebufferingImpact - switchCandidate.rebufferingImpact;\n let minimumTimeSaving = 0.5; // If we are already rebuffering, increase the amount of variance we add to the\n // potential round trip time of the new request so that we are not too aggressive\n // with switching to a playlist that might save us a fraction of a second.\n\n if (timeUntilRebuffer$1 <= TIME_FUDGE_FACTOR) {\n minimumTimeSaving = 1;\n }\n\n if (!switchCandidate.playlist || switchCandidate.playlist.uri === this.playlist_.uri || timeSavedBySwitching < minimumTimeSaving) {\n return;\n } // set the bandwidth to that of the desired playlist being sure to scale by\n // BANDWIDTH_VARIANCE and add one so the playlist selector does not exclude it\n // don't trigger a bandwidthupdate as the bandwidth is artifial\n\n\n this.bandwidth = switchCandidate.playlist.attributes.BANDWIDTH * Config.BANDWIDTH_VARIANCE + 1;\n this.trigger('earlyabort');\n }\n\n handleAbort_(segmentInfo) {\n this.logger_(`Aborting ${segmentInfoString(segmentInfo)}`);\n this.mediaRequestsAborted += 1;\n }\n /**\n * XHR `progress` event handler\n *\n * @param {Event}\n * The XHR `progress` event\n * @param {Object} simpleSegment\n * A simplified segment object copy\n * @private\n */\n\n\n handleProgress_(event, simpleSegment) {\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n }\n\n this.trigger('progress');\n }\n\n handleTrackInfo_(simpleSegment, trackInfo) {\n const {\n hasAudio,\n hasVideo\n } = trackInfo;\n const metadata = {\n segmentInfo: segmentInfoPayload({\n type: this.loaderType_,\n segment: simpleSegment\n }),\n trackInfo: {\n hasAudio,\n hasVideo\n }\n };\n this.trigger({\n type: 'segmenttransmuxingtrackinfoavailable',\n metadata\n });\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n }\n\n if (this.checkForIllegalMediaSwitch(trackInfo)) {\n return;\n }\n\n trackInfo = trackInfo || {}; // When we have track info, determine what media types this loader is dealing with.\n // Guard against cases where we're not getting track info at all until we are\n // certain that all streams will provide it.\n\n if (!shallowEqual(this.currentMediaInfo_, trackInfo)) {\n this.appendInitSegment_ = {\n audio: true,\n video: true\n };\n this.startingMediaInfo_ = trackInfo;\n this.currentMediaInfo_ = trackInfo;\n this.logger_('trackinfo update', trackInfo);\n this.trigger('trackinfo');\n } // trackinfo may cause an abort if the trackinfo\n // causes a codec change to an unsupported codec.\n\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n } // set trackinfo on the pending segment so that\n // it can append.\n\n\n this.pendingSegment_.trackInfo = trackInfo; // check if any calls were waiting on the track info\n\n if (this.hasEnoughInfoToAppend_()) {\n this.processCallQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n }\n\n handleTimingInfo_(simpleSegment, mediaType, timeType, time) {\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n }\n\n const segmentInfo = this.pendingSegment_;\n const timingInfoProperty = timingInfoPropertyForMedia(mediaType);\n segmentInfo[timingInfoProperty] = segmentInfo[timingInfoProperty] || {};\n segmentInfo[timingInfoProperty][timeType] = time;\n this.logger_(`timinginfo: ${mediaType} - ${timeType} - ${time}`); // check if any calls were waiting on the timing info\n\n if (this.hasEnoughInfoToAppend_()) {\n this.processCallQueue_();\n } else {\n checkAndFixTimelines(this);\n }\n }\n\n handleCaptions_(simpleSegment, captionData) {\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n } // This could only happen with fmp4 segments, but\n // should still not happen in general\n\n\n if (captionData.length === 0) {\n this.logger_('SegmentLoader received no captions from a caption event');\n return;\n }\n\n const segmentInfo = this.pendingSegment_; // Wait until we have some video data so that caption timing\n // can be adjusted by the timestamp offset\n\n if (!segmentInfo.hasAppendedData_) {\n this.metadataQueue_.caption.push(this.handleCaptions_.bind(this, simpleSegment, captionData));\n return;\n }\n\n const timestampOffset = this.sourceUpdater_.videoTimestampOffset() === null ? this.sourceUpdater_.audioTimestampOffset() : this.sourceUpdater_.videoTimestampOffset();\n const captionTracks = {}; // get total start/end and captions for each track/stream\n\n captionData.forEach(caption => {\n // caption.stream is actually a track name...\n // set to the existing values in tracks or default values\n captionTracks[caption.stream] = captionTracks[caption.stream] || {\n // Infinity, as any other value will be less than this\n startTime: Infinity,\n captions: [],\n // 0 as an other value will be more than this\n endTime: 0\n };\n const captionTrack = captionTracks[caption.stream];\n captionTrack.startTime = Math.min(captionTrack.startTime, caption.startTime + timestampOffset);\n captionTrack.endTime = Math.max(captionTrack.endTime, caption.endTime + timestampOffset);\n captionTrack.captions.push(caption);\n });\n Object.keys(captionTracks).forEach(trackName => {\n const {\n startTime,\n endTime,\n captions\n } = captionTracks[trackName];\n const inbandTextTracks = this.inbandTextTracks_;\n this.logger_(`adding cues from ${startTime} -> ${endTime} for ${trackName}`);\n createCaptionsTrackIfNotExists(inbandTextTracks, this.vhs_.tech_, trackName); // clear out any cues that start and end at the same time period for the same track.\n // We do this because a rendition change that also changes the timescale for captions\n // will result in captions being re-parsed for certain segments. If we add them again\n // without clearing we will have two of the same captions visible.\n\n removeCuesFromTrack(startTime, endTime, inbandTextTracks[trackName]);\n addCaptionData({\n captionArray: captions,\n inbandTextTracks,\n timestampOffset\n });\n }); // Reset stored captions since we added parsed\n // captions to a text track at this point\n\n if (this.transmuxer_) {\n this.transmuxer_.postMessage({\n action: 'clearParsedMp4Captions'\n });\n }\n }\n\n handleId3_(simpleSegment, id3Frames, dispatchType) {\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n }\n\n const segmentInfo = this.pendingSegment_; // we need to have appended data in order for the timestamp offset to be set\n\n if (!segmentInfo.hasAppendedData_) {\n this.metadataQueue_.id3.push(this.handleId3_.bind(this, simpleSegment, id3Frames, dispatchType));\n return;\n }\n\n this.addMetadataToTextTrack(dispatchType, id3Frames, this.duration_());\n }\n\n processMetadataQueue_() {\n this.metadataQueue_.id3.forEach(fn => fn());\n this.metadataQueue_.caption.forEach(fn => fn());\n this.metadataQueue_.id3 = [];\n this.metadataQueue_.caption = [];\n }\n\n processCallQueue_() {\n const callQueue = this.callQueue_; // Clear out the queue before the queued functions are run, since some of the\n // functions may check the length of the load queue and default to pushing themselves\n // back onto the queue.\n\n this.callQueue_ = [];\n callQueue.forEach(fun => fun());\n }\n\n processLoadQueue_() {\n const loadQueue = this.loadQueue_; // Clear out the queue before the queued functions are run, since some of the\n // functions may check the length of the load queue and default to pushing themselves\n // back onto the queue.\n\n this.loadQueue_ = [];\n loadQueue.forEach(fun => fun());\n }\n /**\n * Determines whether the loader has enough info to load the next segment.\n *\n * @return {boolean}\n * Whether or not the loader has enough info to load the next segment\n */\n\n\n hasEnoughInfoToLoad_() {\n // Since primary timing goes by video, only the audio loader potentially needs to wait\n // to load.\n if (this.loaderType_ !== 'audio') {\n return true;\n }\n\n const segmentInfo = this.pendingSegment_; // A fill buffer must have already run to establish a pending segment before there's\n // enough info to load.\n\n if (!segmentInfo) {\n return false;\n } // The first segment can and should be loaded immediately so that source buffers are\n // created together (before appending). Source buffer creation uses the presence of\n // audio and video data to determine whether to create audio/video source buffers, and\n // uses processed (transmuxed or parsed) media to determine the types required.\n\n\n if (!this.getCurrentMediaInfo_()) {\n return true;\n }\n\n if ( // Technically, instead of waiting to load a segment on timeline changes, a segment\n // can be requested and downloaded and only wait before it is transmuxed or parsed.\n // But in practice, there are a few reasons why it is better to wait until a loader\n // is ready to append that segment before requesting and downloading:\n //\n // 1. Because audio and main loaders cross discontinuities together, if this loader\n // is waiting for the other to catch up, then instead of requesting another\n // segment and using up more bandwidth, by not yet loading, more bandwidth is\n // allotted to the loader currently behind.\n // 2. media-segment-request doesn't have to have logic to consider whether a segment\n // is ready to be processed or not, isolating the queueing behavior to the loader.\n // 3. The audio loader bases some of its segment properties on timing information\n // provided by the main loader, meaning that, if the logic for waiting on\n // processing was in media-segment-request, then it would also need to know how\n // to re-generate the segment information after the main loader caught up.\n shouldWaitForTimelineChange({\n timelineChangeController: this.timelineChangeController_,\n currentTimeline: this.currentTimeline_,\n segmentTimeline: segmentInfo.timeline,\n loaderType: this.loaderType_,\n audioDisabled: this.audioDisabled_\n })) {\n return false;\n }\n\n return true;\n }\n\n getCurrentMediaInfo_(segmentInfo = this.pendingSegment_) {\n return segmentInfo && segmentInfo.trackInfo || this.currentMediaInfo_;\n }\n\n getMediaInfo_(segmentInfo = this.pendingSegment_) {\n return this.getCurrentMediaInfo_(segmentInfo) || this.startingMediaInfo_;\n }\n\n getPendingSegmentPlaylist() {\n return this.pendingSegment_ ? this.pendingSegment_.playlist : null;\n }\n\n hasEnoughInfoToAppend_() {\n if (!this.sourceUpdater_.ready()) {\n return false;\n } // If content needs to be removed or the loader is waiting on an append reattempt,\n // then no additional content should be appended until the prior append is resolved.\n\n\n if (this.waitingOnRemove_ || this.quotaExceededErrorRetryTimeout_) {\n return false;\n }\n\n const segmentInfo = this.pendingSegment_;\n const trackInfo = this.getCurrentMediaInfo_(); // no segment to append any data for or\n // we do not have information on this specific\n // segment yet\n\n if (!segmentInfo || !trackInfo) {\n return false;\n }\n\n const {\n hasAudio,\n hasVideo,\n isMuxed\n } = trackInfo;\n\n if (hasVideo && !segmentInfo.videoTimingInfo) {\n return false;\n } // muxed content only relies on video timing information for now.\n\n\n if (hasAudio && !this.audioDisabled_ && !isMuxed && !segmentInfo.audioTimingInfo) {\n return false;\n } // we need to allow an append here even if we're moving to different timelines.\n\n\n if (shouldWaitForTimelineChange({\n timelineChangeController: this.timelineChangeController_,\n currentTimeline: this.currentTimeline_,\n segmentTimeline: segmentInfo.timeline,\n loaderType: this.loaderType_,\n audioDisabled: this.audioDisabled_\n })) {\n return false;\n }\n\n return true;\n }\n\n handleData_(simpleSegment, result) {\n this.earlyAbortWhenNeeded_(simpleSegment.stats);\n\n if (this.checkForAbort_(simpleSegment.requestId)) {\n return;\n } // If there's anything in the call queue, then this data came later and should be\n // executed after the calls currently queued.\n\n\n if (this.callQueue_.length || !this.hasEnoughInfoToAppend_()) {\n checkAndFixTimelines(this);\n this.callQueue_.push(this.handleData_.bind(this, simpleSegment, result));\n return;\n }\n\n const segmentInfo = this.pendingSegment_; // update the time mapping so we can translate from display time to media time\n\n this.setTimeMapping_(segmentInfo.timeline); // for tracking overall stats\n\n this.updateMediaSecondsLoaded_(segmentInfo.part || segmentInfo.segment); // Note that the state isn't changed from loading to appending. This is because abort\n // logic may change behavior depending on the state, and changing state too early may\n // inflate our estimates of bandwidth. In the future this should be re-examined to\n // note more granular states.\n // don't process and append data if the mediaSource is closed\n\n if (this.mediaSource_.readyState === 'closed') {\n return;\n } // if this request included an initialization segment, save that data\n // to the initSegment cache\n\n\n if (simpleSegment.map) {\n simpleSegment.map = this.initSegmentForMap(simpleSegment.map, true); // move over init segment properties to media request\n\n segmentInfo.segment.map = simpleSegment.map;\n } // if this request included a segment key, save that data in the cache\n\n\n if (simpleSegment.key) {\n this.segmentKey(simpleSegment.key, true);\n }\n\n segmentInfo.isFmp4 = simpleSegment.isFmp4;\n segmentInfo.timingInfo = segmentInfo.timingInfo || {};\n\n if (segmentInfo.isFmp4) {\n this.trigger('fmp4');\n segmentInfo.timingInfo.start = segmentInfo[timingInfoPropertyForMedia(result.type)].start;\n } else {\n const trackInfo = this.getCurrentMediaInfo_();\n const useVideoTimingInfo = this.loaderType_ === 'main' && trackInfo && trackInfo.hasVideo;\n let firstVideoFrameTimeForData;\n\n if (useVideoTimingInfo) {\n firstVideoFrameTimeForData = segmentInfo.videoTimingInfo.start;\n } // Segment loader knows more about segment timing than the transmuxer (in certain\n // aspects), so make any changes required for a more accurate start time.\n // Don't set the end time yet, as the segment may not be finished processing.\n\n\n segmentInfo.timingInfo.start = this.trueSegmentStart_({\n currentStart: segmentInfo.timingInfo.start,\n playlist: segmentInfo.playlist,\n mediaIndex: segmentInfo.mediaIndex,\n currentVideoTimestampOffset: this.sourceUpdater_.videoTimestampOffset(),\n useVideoTimingInfo,\n firstVideoFrameTimeForData,\n videoTimingInfo: segmentInfo.videoTimingInfo,\n audioTimingInfo: segmentInfo.audioTimingInfo\n });\n } // Init segments for audio and video only need to be appended in certain cases. Now\n // that data is about to be appended, we can check the final cases to determine\n // whether we should append an init segment.\n\n\n this.updateAppendInitSegmentStatus(segmentInfo, result.type); // Timestamp offset should be updated once we get new data and have its timing info,\n // as we use the start of the segment to offset the best guess (playlist provided)\n // timestamp offset.\n\n this.updateSourceBufferTimestampOffset_(segmentInfo); // if this is a sync request we need to determine whether it should\n // be appended or not.\n\n if (segmentInfo.isSyncRequest) {\n // first save/update our timing info for this segment.\n // this is what allows us to choose an accurate segment\n // and the main reason we make a sync request.\n this.updateTimingInfoEnd_(segmentInfo);\n this.syncController_.saveSegmentTimingInfo({\n segmentInfo,\n shouldSaveTimelineMapping: this.loaderType_ === 'main'\n });\n const next = this.chooseNextRequest_(); // If the sync request isn't the segment that would be requested next\n // after taking into account its timing info, do not append it.\n\n if (next.mediaIndex !== segmentInfo.mediaIndex || next.partIndex !== segmentInfo.partIndex) {\n this.logger_('sync segment was incorrect, not appending');\n return;\n } // otherwise append it like any other segment as our guess was correct.\n\n\n this.logger_('sync segment was correct, appending');\n } // Save some state so that in the future anything waiting on first append (and/or\n // timestamp offset(s)) can process immediately. While the extra state isn't optimal,\n // we need some notion of whether the timestamp offset or other relevant information\n // has had a chance to be set.\n\n\n segmentInfo.hasAppendedData_ = true; // Now that the timestamp offset should be set, we can append any waiting ID3 tags.\n\n this.processMetadataQueue_();\n this.appendData_(segmentInfo, result);\n }\n\n updateAppendInitSegmentStatus(segmentInfo, type) {\n // alt audio doesn't manage timestamp offset\n if (this.loaderType_ === 'main' && typeof segmentInfo.timestampOffset === 'number' && // in the case that we're handling partial data, we don't want to append an init\n // segment for each chunk\n !segmentInfo.changedTimestampOffset) {\n // if the timestamp offset changed, the timeline may have changed, so we have to re-\n // append init segments\n this.appendInitSegment_ = {\n audio: true,\n video: true\n };\n }\n\n if (this.playlistOfLastInitSegment_[type] !== segmentInfo.playlist) {\n // make sure we append init segment on playlist changes, in case the media config\n // changed\n this.appendInitSegment_[type] = true;\n }\n }\n\n getInitSegmentAndUpdateState_({\n type,\n initSegment,\n map,\n playlist\n }) {\n // \"The EXT-X-MAP tag specifies how to obtain the Media Initialization Section\n // (Section 3) required to parse the applicable Media Segments. It applies to every\n // Media Segment that appears after it in the Playlist until the next EXT-X-MAP tag\n // or until the end of the playlist.\"\n // https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.5\n if (map) {\n const id = initSegmentId(map);\n\n if (this.activeInitSegmentId_ === id) {\n // don't need to re-append the init segment if the ID matches\n return null;\n } // a map-specified init segment takes priority over any transmuxed (or otherwise\n // obtained) init segment\n //\n // this also caches the init segment for later use\n\n\n initSegment = this.initSegmentForMap(map, true).bytes;\n this.activeInitSegmentId_ = id;\n } // We used to always prepend init segments for video, however, that shouldn't be\n // necessary. Instead, we should only append on changes, similar to what we've always\n // done for audio. This is more important (though may not be that important) for\n // frame-by-frame appending for LHLS, simply because of the increased quantity of\n // appends.\n\n\n if (initSegment && this.appendInitSegment_[type]) {\n // Make sure we track the playlist that we last used for the init segment, so that\n // we can re-append the init segment in the event that we get data from a new\n // playlist. Discontinuities and track changes are handled in other sections.\n this.playlistOfLastInitSegment_[type] = playlist; // Disable future init segment appends for this type. Until a change is necessary.\n\n this.appendInitSegment_[type] = false; // we need to clear out the fmp4 active init segment id, since\n // we are appending the muxer init segment\n\n this.activeInitSegmentId_ = null;\n return initSegment;\n }\n\n return null;\n }\n\n handleQuotaExceededError_({\n segmentInfo,\n type,\n bytes\n }, error) {\n const audioBuffered = this.sourceUpdater_.audioBuffered();\n const videoBuffered = this.sourceUpdater_.videoBuffered(); // For now we're ignoring any notion of gaps in the buffer, but they, in theory,\n // should be cleared out during the buffer removals. However, log in case it helps\n // debug.\n\n if (audioBuffered.length > 1) {\n this.logger_('On QUOTA_EXCEEDED_ERR, found gaps in the audio buffer: ' + timeRangesToArray(audioBuffered).join(', '));\n }\n\n if (videoBuffered.length > 1) {\n this.logger_('On QUOTA_EXCEEDED_ERR, found gaps in the video buffer: ' + timeRangesToArray(videoBuffered).join(', '));\n }\n\n const audioBufferStart = audioBuffered.length ? audioBuffered.start(0) : 0;\n const audioBufferEnd = audioBuffered.length ? audioBuffered.end(audioBuffered.length - 1) : 0;\n const videoBufferStart = videoBuffered.length ? videoBuffered.start(0) : 0;\n const videoBufferEnd = videoBuffered.length ? videoBuffered.end(videoBuffered.length - 1) : 0;\n\n if (audioBufferEnd - audioBufferStart <= MIN_BACK_BUFFER && videoBufferEnd - videoBufferStart <= MIN_BACK_BUFFER) {\n // Can't remove enough buffer to make room for new segment (or the browser doesn't\n // allow for appends of segments this size). In the future, it may be possible to\n // split up the segment and append in pieces, but for now, error out this playlist\n // in an attempt to switch to a more manageable rendition.\n this.logger_('On QUOTA_EXCEEDED_ERR, single segment too large to append to ' + 'buffer, triggering an error. ' + `Appended byte length: ${bytes.byteLength}, ` + `audio buffer: ${timeRangesToArray(audioBuffered).join(', ')}, ` + `video buffer: ${timeRangesToArray(videoBuffered).join(', ')}, `);\n this.error({\n message: 'Quota exceeded error with append of a single segment of content',\n excludeUntil: Infinity\n });\n this.trigger('error');\n return;\n } // To try to resolve the quota exceeded error, clear back buffer and retry. This means\n // that the segment-loader should block on future events until this one is handled, so\n // that it doesn't keep moving onto further segments. Adding the call to the call\n // queue will prevent further appends until waitingOnRemove_ and\n // quotaExceededErrorRetryTimeout_ are cleared.\n //\n // Note that this will only block the current loader. In the case of demuxed content,\n // the other load may keep filling as fast as possible. In practice, this should be\n // OK, as it is a rare case when either audio has a high enough bitrate to fill up a\n // source buffer, or video fills without enough room for audio to append (and without\n // the availability of clearing out seconds of back buffer to make room for audio).\n // But it might still be good to handle this case in the future as a TODO.\n\n\n this.waitingOnRemove_ = true;\n this.callQueue_.push(this.appendToSourceBuffer_.bind(this, {\n segmentInfo,\n type,\n bytes\n }));\n const currentTime = this.currentTime_(); // Try to remove as much audio and video as possible to make room for new content\n // before retrying.\n\n const timeToRemoveUntil = currentTime - MIN_BACK_BUFFER;\n this.logger_(`On QUOTA_EXCEEDED_ERR, removing audio/video from 0 to ${timeToRemoveUntil}`);\n this.remove(0, timeToRemoveUntil, () => {\n this.logger_(`On QUOTA_EXCEEDED_ERR, retrying append in ${MIN_BACK_BUFFER}s`);\n this.waitingOnRemove_ = false; // wait the length of time alotted in the back buffer to prevent wasted\n // attempts (since we can't clear less than the minimum)\n\n this.quotaExceededErrorRetryTimeout_ = window$1.setTimeout(() => {\n this.logger_('On QUOTA_EXCEEDED_ERR, re-processing call queue');\n this.quotaExceededErrorRetryTimeout_ = null;\n this.processCallQueue_();\n }, MIN_BACK_BUFFER * 1000);\n }, true);\n }\n\n handleAppendError_({\n segmentInfo,\n type,\n bytes\n }, error) {\n // if there's no error, nothing to do\n if (!error) {\n return;\n }\n\n if (error.code === QUOTA_EXCEEDED_ERR) {\n this.handleQuotaExceededError_({\n segmentInfo,\n type,\n bytes\n }); // A quota exceeded error should be recoverable with a future re-append, so no need\n // to trigger an append error.\n\n return;\n }\n\n this.logger_('Received non QUOTA_EXCEEDED_ERR on append', error); // If an append errors, we often can't recover.\n // (see https://w3c.github.io/media-source/#sourcebuffer-append-error).\n //\n // Trigger a special error so that it can be handled separately from normal,\n // recoverable errors.\n\n this.error({\n message: `${type} append of ${bytes.length}b failed for segment ` + `#${segmentInfo.mediaIndex} in playlist ${segmentInfo.playlist.id}`,\n metadata: {\n errorType: videojs.Error.StreamingFailedToAppendSegment\n }\n });\n this.trigger('appenderror');\n }\n\n appendToSourceBuffer_({\n segmentInfo,\n type,\n initSegment,\n data,\n bytes\n }) {\n // If this is a re-append, bytes were already created and don't need to be recreated\n if (!bytes) {\n const segments = [data];\n let byteLength = data.byteLength;\n\n if (initSegment) {\n // if the media initialization segment is changing, append it before the content\n // segment\n segments.unshift(initSegment);\n byteLength += initSegment.byteLength;\n } // Technically we should be OK appending the init segment separately, however, we\n // haven't yet tested that, and prepending is how we have always done things.\n\n\n bytes = concatSegments({\n bytes: byteLength,\n segments\n });\n }\n\n const metadata = {\n segmentInfo: segmentInfoPayload({\n type: this.loaderType_,\n segment: segmentInfo\n })\n };\n this.trigger({\n type: 'segmentappendstart',\n metadata\n });\n this.sourceUpdater_.appendBuffer({\n segmentInfo,\n type,\n bytes\n }, this.handleAppendError_.bind(this, {\n segmentInfo,\n type,\n bytes\n }));\n }\n\n handleSegmentTimingInfo_(type, requestId, segmentTimingInfo) {\n if (!this.pendingSegment_ || requestId !== this.pendingSegment_.requestId) {\n return;\n }\n\n const segment = this.pendingSegment_.segment;\n const timingInfoProperty = `${type}TimingInfo`;\n\n if (!segment[timingInfoProperty]) {\n segment[timingInfoProperty] = {};\n }\n\n segment[timingInfoProperty].transmuxerPrependedSeconds = segmentTimingInfo.prependedContentDuration || 0;\n segment[timingInfoProperty].transmuxedPresentationStart = segmentTimingInfo.start.presentation;\n segment[timingInfoProperty].transmuxedDecodeStart = segmentTimingInfo.start.decode;\n segment[timingInfoProperty].transmuxedPresentationEnd = segmentTimingInfo.end.presentation;\n segment[timingInfoProperty].transmuxedDecodeEnd = segmentTimingInfo.end.decode; // mainly used as a reference for debugging\n\n segment[timingInfoProperty].baseMediaDecodeTime = segmentTimingInfo.baseMediaDecodeTime;\n }\n\n appendData_(segmentInfo, result) {\n const {\n type,\n data\n } = result;\n\n if (!data || !data.byteLength) {\n return;\n }\n\n if (type === 'audio' && this.audioDisabled_) {\n return;\n }\n\n const initSegment = this.getInitSegmentAndUpdateState_({\n type,\n initSegment: result.initSegment,\n playlist: segmentInfo.playlist,\n map: segmentInfo.isFmp4 ? segmentInfo.segment.map : null\n });\n this.appendToSourceBuffer_({\n segmentInfo,\n type,\n initSegment,\n data\n });\n }\n /**\n * load a specific segment from a request into the buffer\n *\n * @private\n */\n\n\n loadSegment_(segmentInfo) {\n this.state = 'WAITING';\n this.pendingSegment_ = segmentInfo;\n this.trimBackBuffer_(segmentInfo);\n\n if (typeof segmentInfo.timestampOffset === 'number') {\n if (this.transmuxer_) {\n this.transmuxer_.postMessage({\n action: 'clearAllMp4Captions'\n });\n }\n }\n\n if (!this.hasEnoughInfoToLoad_()) {\n checkAndFixTimelines(this);\n this.loadQueue_.push(() => {\n // regenerate the audioAppendStart, timestampOffset, etc as they\n // may have changed since this function was added to the queue.\n const options = _extends({}, segmentInfo, {\n forceTimestampOffset: true\n });\n\n _extends(segmentInfo, this.generateSegmentInfo_(options));\n\n this.isPendingTimestampOffset_ = false;\n this.updateTransmuxerAndRequestSegment_(segmentInfo);\n });\n return;\n }\n\n this.updateTransmuxerAndRequestSegment_(segmentInfo);\n }\n\n updateTransmuxerAndRequestSegment_(segmentInfo) {\n // We'll update the source buffer's timestamp offset once we have transmuxed data, but\n // the transmuxer still needs to be updated before then.\n //\n // Even though keepOriginalTimestamps is set to true for the transmuxer, timestamp\n // offset must be passed to the transmuxer for stream correcting adjustments.\n if (this.shouldUpdateTransmuxerTimestampOffset_(segmentInfo.timestampOffset)) {\n this.gopBuffer_.length = 0; // gopsToAlignWith was set before the GOP buffer was cleared\n\n segmentInfo.gopsToAlignWith = [];\n this.timeMapping_ = 0; // reset values in the transmuxer since a discontinuity should start fresh\n\n this.transmuxer_.postMessage({\n action: 'reset'\n });\n this.transmuxer_.postMessage({\n action: 'setTimestampOffset',\n timestampOffset: segmentInfo.timestampOffset\n });\n }\n\n const simpleSegment = this.createSimplifiedSegmentObj_(segmentInfo);\n const isEndOfStream = this.isEndOfStream_(segmentInfo.mediaIndex, segmentInfo.playlist, segmentInfo.partIndex);\n const isWalkingForward = this.mediaIndex !== null;\n const isDiscontinuity = segmentInfo.timeline !== this.currentTimeline_ && // currentTimeline starts at -1, so we shouldn't end the timeline switching to 0,\n // the first timeline\n segmentInfo.timeline > 0;\n const isEndOfTimeline = isEndOfStream || isWalkingForward && isDiscontinuity;\n this.logger_(`Requesting\n${compactSegmentUrlDescription(segmentInfo.uri)}\n${segmentInfoString(segmentInfo)}`); // If there's an init segment associated with this segment, but it is not cached (identified by a lack of bytes),\n // then this init segment has never been seen before and should be appended.\n //\n // At this point the content type (audio/video or both) is not yet known, but it should be safe to set\n // both to true and leave the decision of whether to append the init segment to append time.\n\n if (simpleSegment.map && !simpleSegment.map.bytes) {\n this.logger_('going to request init segment.');\n this.appendInitSegment_ = {\n video: true,\n audio: true\n };\n }\n\n segmentInfo.abortRequests = mediaSegmentRequest({\n xhr: this.vhs_.xhr,\n xhrOptions: this.xhrOptions_,\n decryptionWorker: this.decrypter_,\n segment: simpleSegment,\n abortFn: this.handleAbort_.bind(this, segmentInfo),\n progressFn: this.handleProgress_.bind(this),\n trackInfoFn: this.handleTrackInfo_.bind(this),\n timingInfoFn: this.handleTimingInfo_.bind(this),\n videoSegmentTimingInfoFn: this.handleSegmentTimingInfo_.bind(this, 'video', segmentInfo.requestId),\n audioSegmentTimingInfoFn: this.handleSegmentTimingInfo_.bind(this, 'audio', segmentInfo.requestId),\n captionsFn: this.handleCaptions_.bind(this),\n isEndOfTimeline,\n endedTimelineFn: () => {\n this.logger_('received endedtimeline callback');\n },\n id3Fn: this.handleId3_.bind(this),\n dataFn: this.handleData_.bind(this),\n doneFn: this.segmentRequestFinished_.bind(this),\n onTransmuxerLog: ({\n message,\n level,\n stream\n }) => {\n this.logger_(`${segmentInfoString(segmentInfo)} logged from transmuxer stream ${stream} as a ${level}: ${message}`);\n },\n triggerSegmentEventFn: ({\n type,\n segment,\n keyInfo,\n trackInfo,\n timingInfo\n }) => {\n const segInfo = segmentInfoPayload({\n segment\n });\n const metadata = {\n segmentInfo: segInfo\n }; // add other properties if necessary.\n\n if (keyInfo) {\n metadata.keyInfo = keyInfo;\n }\n\n if (trackInfo) {\n metadata.trackInfo = trackInfo;\n }\n\n if (timingInfo) {\n metadata.timingInfo = timingInfo;\n }\n\n this.trigger({\n type,\n metadata\n });\n }\n });\n }\n /**\n * trim the back buffer so that we don't have too much data\n * in the source buffer\n *\n * @private\n *\n * @param {Object} segmentInfo - the current segment\n */\n\n\n trimBackBuffer_(segmentInfo) {\n const removeToTime = safeBackBufferTrimTime(this.seekable_(), this.currentTime_(), this.playlist_.targetDuration || 10); // Chrome has a hard limit of 150MB of\n // buffer and a very conservative \"garbage collector\"\n // We manually clear out the old buffer to ensure\n // we don't trigger the QuotaExceeded error\n // on the source buffer during subsequent appends\n\n if (removeToTime > 0) {\n this.remove(0, removeToTime);\n }\n }\n /**\n * created a simplified copy of the segment object with just the\n * information necessary to perform the XHR and decryption\n *\n * @private\n *\n * @param {Object} segmentInfo - the current segment\n * @return {Object} a simplified segment object copy\n */\n\n\n createSimplifiedSegmentObj_(segmentInfo) {\n const segment = segmentInfo.segment;\n const part = segmentInfo.part;\n const isEncrypted = segmentInfo.segment.key || segmentInfo.segment.map && segmentInfo.segment.map.key;\n const isMediaInitialization = segmentInfo.segment.map && !segmentInfo.segment.map.bytes;\n const simpleSegment = {\n resolvedUri: part ? part.resolvedUri : segment.resolvedUri,\n byterange: part ? part.byterange : segment.byterange,\n requestId: segmentInfo.requestId,\n transmuxer: segmentInfo.transmuxer,\n audioAppendStart: segmentInfo.audioAppendStart,\n gopsToAlignWith: segmentInfo.gopsToAlignWith,\n part: segmentInfo.part,\n type: this.loaderType_,\n start: segmentInfo.startOfSegment,\n duration: segmentInfo.duration,\n isEncrypted,\n isMediaInitialization\n };\n const previousSegment = segmentInfo.playlist.segments[segmentInfo.mediaIndex - 1];\n\n if (previousSegment && previousSegment.timeline === segment.timeline) {\n // The baseStartTime of a segment is used to handle rollover when probing the TS\n // segment to retrieve timing information. Since the probe only looks at the media's\n // times (e.g., PTS and DTS values of the segment), and doesn't consider the\n // player's time (e.g., player.currentTime()), baseStartTime should reflect the\n // media time as well. transmuxedDecodeEnd represents the end time of a segment, in\n // seconds of media time, so should be used here. The previous segment is used since\n // the end of the previous segment should represent the beginning of the current\n // segment, so long as they are on the same timeline.\n if (previousSegment.videoTimingInfo) {\n simpleSegment.baseStartTime = previousSegment.videoTimingInfo.transmuxedDecodeEnd;\n } else if (previousSegment.audioTimingInfo) {\n simpleSegment.baseStartTime = previousSegment.audioTimingInfo.transmuxedDecodeEnd;\n }\n }\n\n if (segment.key) {\n // if the media sequence is greater than 2^32, the IV will be incorrect\n // assuming 10s segments, that would be about 1300 years\n const iv = segment.key.iv || new Uint32Array([0, 0, 0, segmentInfo.mediaIndex + segmentInfo.playlist.mediaSequence]);\n simpleSegment.key = this.segmentKey(segment.key);\n simpleSegment.key.iv = iv;\n }\n\n if (segment.map) {\n simpleSegment.map = this.initSegmentForMap(segment.map);\n }\n\n return simpleSegment;\n }\n\n saveTransferStats_(stats) {\n // every request counts as a media request even if it has been aborted\n // or canceled due to a timeout\n this.mediaRequests += 1;\n\n if (stats) {\n this.mediaBytesTransferred += stats.bytesReceived;\n this.mediaTransferDuration += stats.roundTripTime;\n }\n }\n\n saveBandwidthRelatedStats_(duration, stats) {\n // byteLength will be used for throughput, and should be based on bytes receieved,\n // which we only know at the end of the request and should reflect total bytes\n // downloaded rather than just bytes processed from components of the segment\n this.pendingSegment_.byteLength = stats.bytesReceived;\n\n if (duration < MIN_SEGMENT_DURATION_TO_SAVE_STATS) {\n this.logger_(`Ignoring segment's bandwidth because its duration of ${duration}` + ` is less than the min to record ${MIN_SEGMENT_DURATION_TO_SAVE_STATS}`);\n return;\n }\n\n const metadata = {\n bandwidthInfo: {\n from: this.bandwidth,\n to: stats.bandwidth\n }\n }; // player event with payload\n\n this.trigger({\n type: 'bandwidthupdated',\n metadata\n });\n this.bandwidth = stats.bandwidth;\n this.roundTrip = stats.roundTripTime;\n }\n\n handleTimeout_() {\n // although the VTT segment loader bandwidth isn't really used, it's good to\n // maintain functinality between segment loaders\n this.mediaRequestsTimedout += 1;\n this.bandwidth = 1;\n this.roundTrip = NaN;\n this.trigger('bandwidthupdate');\n this.trigger('timeout');\n }\n /**\n * Handle the callback from the segmentRequest function and set the\n * associated SegmentLoader state and errors if necessary\n *\n * @private\n */\n\n\n segmentRequestFinished_(error, simpleSegment, result) {\n // TODO handle special cases, e.g., muxed audio/video but only audio in the segment\n // check the call queue directly since this function doesn't need to deal with any\n // data, and can continue even if the source buffers are not set up and we didn't get\n // any data from the segment\n if (this.callQueue_.length) {\n this.callQueue_.push(this.segmentRequestFinished_.bind(this, error, simpleSegment, result));\n return;\n }\n\n this.saveTransferStats_(simpleSegment.stats); // The request was aborted and the SegmentLoader has already been reset\n\n if (!this.pendingSegment_) {\n return;\n } // the request was aborted and the SegmentLoader has already started\n // another request. this can happen when the timeout for an aborted\n // request triggers due to a limitation in the XHR library\n // do not count this as any sort of request or we risk double-counting\n\n\n if (simpleSegment.requestId !== this.pendingSegment_.requestId) {\n return;\n } // an error occurred from the active pendingSegment_ so reset everything\n\n\n if (error) {\n this.pendingSegment_ = null;\n this.state = 'READY'; // aborts are not a true error condition and nothing corrective needs to be done\n\n if (error.code === REQUEST_ERRORS.ABORTED) {\n return;\n }\n\n this.pause(); // the error is really just that at least one of the requests timed-out\n // set the bandwidth to a very low value and trigger an ABR switch to\n // take emergency action\n\n if (error.code === REQUEST_ERRORS.TIMEOUT) {\n this.handleTimeout_();\n return;\n } // if control-flow has arrived here, then the error is real\n // emit an error event to exclude the current playlist\n\n\n this.mediaRequestsErrored += 1;\n this.error(error);\n this.trigger('error');\n return;\n }\n\n const segmentInfo = this.pendingSegment_; // the response was a success so set any bandwidth stats the request\n // generated for ABR purposes\n\n this.saveBandwidthRelatedStats_(segmentInfo.duration, simpleSegment.stats);\n segmentInfo.endOfAllRequests = simpleSegment.endOfAllRequests;\n\n if (result.gopInfo) {\n this.gopBuffer_ = updateGopBuffer(this.gopBuffer_, result.gopInfo, this.safeAppend_);\n } // Although we may have already started appending on progress, we shouldn't switch the\n // state away from loading until we are officially done loading the segment data.\n\n\n this.state = 'APPENDING'; // used for testing\n\n this.trigger('appending');\n this.waitForAppendsToComplete_(segmentInfo);\n }\n\n setTimeMapping_(timeline) {\n const timelineMapping = this.syncController_.mappingForTimeline(timeline);\n\n if (timelineMapping !== null) {\n this.timeMapping_ = timelineMapping;\n }\n }\n\n updateMediaSecondsLoaded_(segment) {\n if (typeof segment.start === 'number' && typeof segment.end === 'number') {\n this.mediaSecondsLoaded += segment.end - segment.start;\n } else {\n this.mediaSecondsLoaded += segment.duration;\n }\n }\n\n shouldUpdateTransmuxerTimestampOffset_(timestampOffset) {\n if (timestampOffset === null) {\n return false;\n } // note that we're potentially using the same timestamp offset for both video and\n // audio\n\n\n if (this.loaderType_ === 'main' && timestampOffset !== this.sourceUpdater_.videoTimestampOffset()) {\n return true;\n }\n\n if (!this.audioDisabled_ && timestampOffset !== this.sourceUpdater_.audioTimestampOffset()) {\n return true;\n }\n\n return false;\n }\n\n trueSegmentStart_({\n currentStart,\n playlist,\n mediaIndex,\n firstVideoFrameTimeForData,\n currentVideoTimestampOffset,\n useVideoTimingInfo,\n videoTimingInfo,\n audioTimingInfo\n }) {\n if (typeof currentStart !== 'undefined') {\n // if start was set once, keep using it\n return currentStart;\n }\n\n if (!useVideoTimingInfo) {\n return audioTimingInfo.start;\n }\n\n const previousSegment = playlist.segments[mediaIndex - 1]; // The start of a segment should be the start of the first full frame contained\n // within that segment. Since the transmuxer maintains a cache of incomplete data\n // from and/or the last frame seen, the start time may reflect a frame that starts\n // in the previous segment. Check for that case and ensure the start time is\n // accurate for the segment.\n\n if (mediaIndex === 0 || !previousSegment || typeof previousSegment.start === 'undefined' || previousSegment.end !== firstVideoFrameTimeForData + currentVideoTimestampOffset) {\n return firstVideoFrameTimeForData;\n }\n\n return videoTimingInfo.start;\n }\n\n waitForAppendsToComplete_(segmentInfo) {\n const trackInfo = this.getCurrentMediaInfo_(segmentInfo);\n\n if (!trackInfo) {\n this.error({\n message: 'No starting media returned, likely due to an unsupported media format.',\n playlistExclusionDuration: Infinity\n });\n this.trigger('error');\n return;\n } // Although transmuxing is done, appends may not yet be finished. Throw a marker\n // on each queue this loader is responsible for to ensure that the appends are\n // complete.\n\n\n const {\n hasAudio,\n hasVideo,\n isMuxed\n } = trackInfo;\n const waitForVideo = this.loaderType_ === 'main' && hasVideo;\n const waitForAudio = !this.audioDisabled_ && hasAudio && !isMuxed;\n segmentInfo.waitingOnAppends = 0; // segments with no data\n\n if (!segmentInfo.hasAppendedData_) {\n if (!segmentInfo.timingInfo && typeof segmentInfo.timestampOffset === 'number') {\n // When there's no audio or video data in the segment, there's no audio or video\n // timing information.\n //\n // If there's no audio or video timing information, then the timestamp offset\n // can't be adjusted to the appropriate value for the transmuxer and source\n // buffers.\n //\n // Therefore, the next segment should be used to set the timestamp offset.\n this.isPendingTimestampOffset_ = true;\n } // override settings for metadata only segments\n\n\n segmentInfo.timingInfo = {\n start: 0\n };\n segmentInfo.waitingOnAppends++;\n\n if (!this.isPendingTimestampOffset_) {\n // update the timestampoffset\n this.updateSourceBufferTimestampOffset_(segmentInfo); // make sure the metadata queue is processed even though we have\n // no video/audio data.\n\n this.processMetadataQueue_();\n } // append is \"done\" instantly with no data.\n\n\n this.checkAppendsDone_(segmentInfo);\n return;\n } // Since source updater could call back synchronously, do the increments first.\n\n\n if (waitForVideo) {\n segmentInfo.waitingOnAppends++;\n }\n\n if (waitForAudio) {\n segmentInfo.waitingOnAppends++;\n }\n\n if (waitForVideo) {\n this.sourceUpdater_.videoQueueCallback(this.checkAppendsDone_.bind(this, segmentInfo));\n }\n\n if (waitForAudio) {\n this.sourceUpdater_.audioQueueCallback(this.checkAppendsDone_.bind(this, segmentInfo));\n }\n }\n\n checkAppendsDone_(segmentInfo) {\n if (this.checkForAbort_(segmentInfo.requestId)) {\n return;\n }\n\n segmentInfo.waitingOnAppends--;\n\n if (segmentInfo.waitingOnAppends === 0) {\n this.handleAppendsDone_();\n }\n }\n\n checkForIllegalMediaSwitch(trackInfo) {\n const illegalMediaSwitchError = illegalMediaSwitch(this.loaderType_, this.getCurrentMediaInfo_(), trackInfo);\n\n if (illegalMediaSwitchError) {\n this.error({\n message: illegalMediaSwitchError,\n playlistExclusionDuration: Infinity\n });\n this.trigger('error');\n return true;\n }\n\n return false;\n }\n\n updateSourceBufferTimestampOffset_(segmentInfo) {\n if (segmentInfo.timestampOffset === null || // we don't yet have the start for whatever media type (video or audio) has\n // priority, timing-wise, so we must wait\n typeof segmentInfo.timingInfo.start !== 'number' || // already updated the timestamp offset for this segment\n segmentInfo.changedTimestampOffset || // the alt audio loader should not be responsible for setting the timestamp offset\n this.loaderType_ !== 'main') {\n return;\n }\n\n let didChange = false; // Primary timing goes by video, and audio is trimmed in the transmuxer, meaning that\n // the timing info here comes from video. In the event that the audio is longer than\n // the video, this will trim the start of the audio.\n // This also trims any offset from 0 at the beginning of the media\n\n segmentInfo.timestampOffset -= this.getSegmentStartTimeForTimestampOffsetCalculation_({\n videoTimingInfo: segmentInfo.segment.videoTimingInfo,\n audioTimingInfo: segmentInfo.segment.audioTimingInfo,\n timingInfo: segmentInfo.timingInfo\n }); // In the event that there are part segment downloads, each will try to update the\n // timestamp offset. Retaining this bit of state prevents us from updating in the\n // future (within the same segment), however, there may be a better way to handle it.\n\n segmentInfo.changedTimestampOffset = true;\n\n if (segmentInfo.timestampOffset !== this.sourceUpdater_.videoTimestampOffset()) {\n this.sourceUpdater_.videoTimestampOffset(segmentInfo.timestampOffset);\n didChange = true;\n }\n\n if (segmentInfo.timestampOffset !== this.sourceUpdater_.audioTimestampOffset()) {\n this.sourceUpdater_.audioTimestampOffset(segmentInfo.timestampOffset);\n didChange = true;\n }\n\n if (didChange) {\n this.trigger('timestampoffset');\n }\n }\n\n getSegmentStartTimeForTimestampOffsetCalculation_({\n videoTimingInfo,\n audioTimingInfo,\n timingInfo\n }) {\n if (!this.useDtsForTimestampOffset_) {\n return timingInfo.start;\n }\n\n if (videoTimingInfo && typeof videoTimingInfo.transmuxedDecodeStart === 'number') {\n return videoTimingInfo.transmuxedDecodeStart;\n } // handle audio only\n\n\n if (audioTimingInfo && typeof audioTimingInfo.transmuxedDecodeStart === 'number') {\n return audioTimingInfo.transmuxedDecodeStart;\n } // handle content not transmuxed (e.g., MP4)\n\n\n return timingInfo.start;\n }\n\n updateTimingInfoEnd_(segmentInfo) {\n segmentInfo.timingInfo = segmentInfo.timingInfo || {};\n const trackInfo = this.getMediaInfo_();\n const useVideoTimingInfo = this.loaderType_ === 'main' && trackInfo && trackInfo.hasVideo;\n const prioritizedTimingInfo = useVideoTimingInfo && segmentInfo.videoTimingInfo ? segmentInfo.videoTimingInfo : segmentInfo.audioTimingInfo;\n\n if (!prioritizedTimingInfo) {\n return;\n }\n\n segmentInfo.timingInfo.end = typeof prioritizedTimingInfo.end === 'number' ? // End time may not exist in a case where we aren't parsing the full segment (one\n // current example is the case of fmp4), so use the rough duration to calculate an\n // end time.\n prioritizedTimingInfo.end : prioritizedTimingInfo.start + segmentInfo.duration;\n }\n /**\n * callback to run when appendBuffer is finished. detects if we are\n * in a good state to do things with the data we got, or if we need\n * to wait for more\n *\n * @private\n */\n\n\n handleAppendsDone_() {\n // appendsdone can cause an abort\n if (this.pendingSegment_) {\n const metadata = {\n segmentInfo: segmentInfoPayload({\n type: this.loaderType_,\n segment: this.pendingSegment_\n })\n };\n this.trigger({\n type: 'appendsdone',\n metadata\n });\n }\n\n if (!this.pendingSegment_) {\n this.state = 'READY'; // TODO should this move into this.checkForAbort to speed up requests post abort in\n // all appending cases?\n\n if (!this.paused()) {\n this.monitorBuffer_();\n }\n\n return;\n }\n\n const segmentInfo = this.pendingSegment_;\n\n if (segmentInfo.part && segmentInfo.part.syncInfo) {\n // low-latency flow\n segmentInfo.part.syncInfo.markAppended();\n } else if (segmentInfo.segment.syncInfo) {\n // normal flow\n segmentInfo.segment.syncInfo.markAppended();\n } // Now that the end of the segment has been reached, we can set the end time. It's\n // best to wait until all appends are done so we're sure that the primary media is\n // finished (and we have its end time).\n\n\n this.updateTimingInfoEnd_(segmentInfo);\n\n if (this.shouldSaveSegmentTimingInfo_) {\n // Timeline mappings should only be saved for the main loader. This is for multiple\n // reasons:\n //\n // 1) Only one mapping is saved per timeline, meaning that if both the audio loader\n // and the main loader try to save the timeline mapping, whichever comes later\n // will overwrite the first. In theory this is OK, as the mappings should be the\n // same, however, it breaks for (2)\n // 2) In the event of a live stream, the initial live point will make for a somewhat\n // arbitrary mapping. If audio and video streams are not perfectly in-sync, then\n // the mapping will be off for one of the streams, dependent on which one was\n // first saved (see (1)).\n // 3) Primary timing goes by video in VHS, so the mapping should be video.\n //\n // Since the audio loader will wait for the main loader to load the first segment,\n // the main loader will save the first timeline mapping, and ensure that there won't\n // be a case where audio loads two segments without saving a mapping (thus leading\n // to missing segment timing info).\n this.syncController_.saveSegmentTimingInfo({\n segmentInfo,\n shouldSaveTimelineMapping: this.loaderType_ === 'main'\n });\n }\n\n const segmentDurationMessage = getTroublesomeSegmentDurationMessage(segmentInfo, this.sourceType_);\n\n if (segmentDurationMessage) {\n if (segmentDurationMessage.severity === 'warn') {\n videojs.log.warn(segmentDurationMessage.message);\n } else {\n this.logger_(segmentDurationMessage.message);\n }\n }\n\n this.recordThroughput_(segmentInfo);\n this.pendingSegment_ = null;\n this.state = 'READY';\n\n if (segmentInfo.isSyncRequest) {\n this.trigger('syncinfoupdate'); // if the sync request was not appended\n // then it was not the correct segment.\n // throw it away and use the data it gave us\n // to get the correct one.\n\n if (!segmentInfo.hasAppendedData_) {\n this.logger_(`Throwing away un-appended sync request ${segmentInfoString(segmentInfo)}`);\n return;\n }\n }\n\n this.logger_(`Appended ${segmentInfoString(segmentInfo)}`);\n this.addSegmentMetadataCue_(segmentInfo);\n this.fetchAtBuffer_ = true;\n\n if (this.currentTimeline_ !== segmentInfo.timeline) {\n this.timelineChangeController_.lastTimelineChange({\n type: this.loaderType_,\n from: this.currentTimeline_,\n to: segmentInfo.timeline\n }); // If audio is not disabled, the main segment loader is responsible for updating\n // the audio timeline as well. If the content is video only, this won't have any\n // impact.\n\n if (this.loaderType_ === 'main' && !this.audioDisabled_) {\n this.timelineChangeController_.lastTimelineChange({\n type: 'audio',\n from: this.currentTimeline_,\n to: segmentInfo.timeline\n });\n }\n }\n\n this.currentTimeline_ = segmentInfo.timeline; // We must update the syncinfo to recalculate the seekable range before\n // the following conditional otherwise it may consider this a bad \"guess\"\n // and attempt to resync when the post-update seekable window and live\n // point would mean that this was the perfect segment to fetch\n\n this.trigger('syncinfoupdate');\n const segment = segmentInfo.segment;\n const part = segmentInfo.part;\n const badSegmentGuess = segment.end && this.currentTime_() - segment.end > segmentInfo.playlist.targetDuration * 3;\n const badPartGuess = part && part.end && this.currentTime_() - part.end > segmentInfo.playlist.partTargetDuration * 3; // If we previously appended a segment/part that ends more than 3 part/targetDurations before\n // the currentTime_ that means that our conservative guess was too conservative.\n // In that case, reset the loader state so that we try to use any information gained\n // from the previous request to create a new, more accurate, sync-point.\n\n if (badSegmentGuess || badPartGuess) {\n this.logger_(`bad ${badSegmentGuess ? 'segment' : 'part'} ${segmentInfoString(segmentInfo)}`);\n this.resetEverything();\n return;\n }\n\n const isWalkingForward = this.mediaIndex !== null; // Don't do a rendition switch unless we have enough time to get a sync segment\n // and conservatively guess\n\n if (isWalkingForward) {\n this.trigger('bandwidthupdate');\n }\n\n this.trigger('progress');\n this.mediaIndex = segmentInfo.mediaIndex;\n this.partIndex = segmentInfo.partIndex; // any time an update finishes and the last segment is in the\n // buffer, end the stream. this ensures the \"ended\" event will\n // fire if playback reaches that point.\n\n if (this.isEndOfStream_(segmentInfo.mediaIndex, segmentInfo.playlist, segmentInfo.partIndex)) {\n this.endOfStream();\n } // used for testing\n\n\n this.trigger('appended');\n\n if (segmentInfo.hasAppendedData_) {\n this.mediaAppends++;\n }\n\n if (!this.paused()) {\n this.monitorBuffer_();\n }\n }\n /**\n * Records the current throughput of the decrypt, transmux, and append\n * portion of the semgment pipeline. `throughput.rate` is a the cumulative\n * moving average of the throughput. `throughput.count` is the number of\n * data points in the average.\n *\n * @private\n * @param {Object} segmentInfo the object returned by loadSegment\n */\n\n\n recordThroughput_(segmentInfo) {\n if (segmentInfo.duration < MIN_SEGMENT_DURATION_TO_SAVE_STATS) {\n this.logger_(`Ignoring segment's throughput because its duration of ${segmentInfo.duration}` + ` is less than the min to record ${MIN_SEGMENT_DURATION_TO_SAVE_STATS}`);\n return;\n }\n\n const rate = this.throughput.rate; // Add one to the time to ensure that we don't accidentally attempt to divide\n // by zero in the case where the throughput is ridiculously high\n\n const segmentProcessingTime = Date.now() - segmentInfo.endOfAllRequests + 1; // Multiply by 8000 to convert from bytes/millisecond to bits/second\n\n const segmentProcessingThroughput = Math.floor(segmentInfo.byteLength / segmentProcessingTime * 8 * 1000); // This is just a cumulative moving average calculation:\n // newAvg = oldAvg + (sample - oldAvg) / (sampleCount + 1)\n\n this.throughput.rate += (segmentProcessingThroughput - rate) / ++this.throughput.count;\n }\n /**\n * Adds a cue to the segment-metadata track with some metadata information about the\n * segment\n *\n * @private\n * @param {Object} segmentInfo\n * the object returned by loadSegment\n * @method addSegmentMetadataCue_\n */\n\n\n addSegmentMetadataCue_(segmentInfo) {\n if (!this.segmentMetadataTrack_) {\n return;\n }\n\n const segment = segmentInfo.segment;\n const start = segment.start;\n const end = segment.end; // Do not try adding the cue if the start and end times are invalid.\n\n if (!finite(start) || !finite(end)) {\n return;\n }\n\n removeCuesFromTrack(start, end, this.segmentMetadataTrack_);\n const Cue = window$1.WebKitDataCue || window$1.VTTCue;\n const value = {\n custom: segment.custom,\n dateTimeObject: segment.dateTimeObject,\n dateTimeString: segment.dateTimeString,\n programDateTime: segment.programDateTime,\n bandwidth: segmentInfo.playlist.attributes.BANDWIDTH,\n resolution: segmentInfo.playlist.attributes.RESOLUTION,\n codecs: segmentInfo.playlist.attributes.CODECS,\n byteLength: segmentInfo.byteLength,\n uri: segmentInfo.uri,\n timeline: segmentInfo.timeline,\n playlist: segmentInfo.playlist.id,\n start,\n end\n };\n const data = JSON.stringify(value);\n const cue = new Cue(start, end, data); // Attach the metadata to the value property of the cue to keep consistency between\n // the differences of WebKitDataCue in safari and VTTCue in other browsers\n\n cue.value = value;\n this.segmentMetadataTrack_.addCue(cue);\n }\n\n}\n\nfunction noop() {}\n\nconst toTitleCase = function (string) {\n if (typeof string !== 'string') {\n return string;\n }\n\n return string.replace(/./, w => w.toUpperCase());\n};\n\n/**\n * @file source-updater.js\n */\nconst bufferTypes = ['video', 'audio'];\n\nconst updating = (type, sourceUpdater) => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`];\n return sourceBuffer && sourceBuffer.updating || sourceUpdater.queuePending[type];\n};\n\nconst nextQueueIndexOfType = (type, queue) => {\n for (let i = 0; i < queue.length; i++) {\n const queueEntry = queue[i];\n\n if (queueEntry.type === 'mediaSource') {\n // If the next entry is a media source entry (uses multiple source buffers), block\n // processing to allow it to go through first.\n return null;\n }\n\n if (queueEntry.type === type) {\n return i;\n }\n }\n\n return null;\n};\n\nconst shiftQueue = (type, sourceUpdater) => {\n if (sourceUpdater.queue.length === 0) {\n return;\n }\n\n let queueIndex = 0;\n let queueEntry = sourceUpdater.queue[queueIndex];\n\n if (queueEntry.type === 'mediaSource') {\n if (!sourceUpdater.updating() && sourceUpdater.mediaSource.readyState !== 'closed') {\n sourceUpdater.queue.shift();\n queueEntry.action(sourceUpdater);\n\n if (queueEntry.doneFn) {\n queueEntry.doneFn();\n } // Only specific source buffer actions must wait for async updateend events. Media\n // Source actions process synchronously. Therefore, both audio and video source\n // buffers are now clear to process the next queue entries.\n\n\n shiftQueue('audio', sourceUpdater);\n shiftQueue('video', sourceUpdater);\n } // Media Source actions require both source buffers, so if the media source action\n // couldn't process yet (because one or both source buffers are busy), block other\n // queue actions until both are available and the media source action can process.\n\n\n return;\n }\n\n if (type === 'mediaSource') {\n // If the queue was shifted by a media source action (this happens when pushing a\n // media source action onto the queue), then it wasn't from an updateend event from an\n // audio or video source buffer, so there's no change from previous state, and no\n // processing should be done.\n return;\n } // Media source queue entries don't need to consider whether the source updater is\n // started (i.e., source buffers are created) as they don't need the source buffers, but\n // source buffer queue entries do.\n\n\n if (!sourceUpdater.ready() || sourceUpdater.mediaSource.readyState === 'closed' || updating(type, sourceUpdater)) {\n return;\n }\n\n if (queueEntry.type !== type) {\n queueIndex = nextQueueIndexOfType(type, sourceUpdater.queue);\n\n if (queueIndex === null) {\n // Either there's no queue entry that uses this source buffer type in the queue, or\n // there's a media source queue entry before the next entry of this type, in which\n // case wait for that action to process first.\n return;\n }\n\n queueEntry = sourceUpdater.queue[queueIndex];\n }\n\n sourceUpdater.queue.splice(queueIndex, 1); // Keep a record that this source buffer type is in use.\n //\n // The queue pending operation must be set before the action is performed in the event\n // that the action results in a synchronous event that is acted upon. For instance, if\n // an exception is thrown that can be handled, it's possible that new actions will be\n // appended to an empty queue and immediately executed, but would not have the correct\n // pending information if this property was set after the action was performed.\n\n sourceUpdater.queuePending[type] = queueEntry;\n queueEntry.action(type, sourceUpdater);\n\n if (!queueEntry.doneFn) {\n // synchronous operation, process next entry\n sourceUpdater.queuePending[type] = null;\n shiftQueue(type, sourceUpdater);\n return;\n }\n};\n\nconst cleanupBuffer = (type, sourceUpdater) => {\n const buffer = sourceUpdater[`${type}Buffer`];\n const titleType = toTitleCase(type);\n\n if (!buffer) {\n return;\n }\n\n buffer.removeEventListener('updateend', sourceUpdater[`on${titleType}UpdateEnd_`]);\n buffer.removeEventListener('error', sourceUpdater[`on${titleType}Error_`]);\n sourceUpdater.codecs[type] = null;\n sourceUpdater[`${type}Buffer`] = null;\n};\n\nconst inSourceBuffers = (mediaSource, sourceBuffer) => mediaSource && sourceBuffer && Array.prototype.indexOf.call(mediaSource.sourceBuffers, sourceBuffer) !== -1;\n\nconst actions = {\n appendBuffer: (bytes, segmentInfo, onError) => (type, sourceUpdater) => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`]; // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n }\n\n sourceUpdater.logger_(`Appending segment ${segmentInfo.mediaIndex}'s ${bytes.length} bytes to ${type}Buffer`);\n\n try {\n sourceBuffer.appendBuffer(bytes);\n } catch (e) {\n sourceUpdater.logger_(`Error with code ${e.code} ` + (e.code === QUOTA_EXCEEDED_ERR ? '(QUOTA_EXCEEDED_ERR) ' : '') + `when appending segment ${segmentInfo.mediaIndex} to ${type}Buffer`);\n sourceUpdater.queuePending[type] = null;\n onError(e);\n }\n },\n remove: (start, end) => (type, sourceUpdater) => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`]; // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n }\n\n sourceUpdater.logger_(`Removing ${start} to ${end} from ${type}Buffer`);\n\n try {\n sourceBuffer.remove(start, end);\n } catch (e) {\n sourceUpdater.logger_(`Remove ${start} to ${end} from ${type}Buffer failed`);\n }\n },\n timestampOffset: offset => (type, sourceUpdater) => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`]; // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n }\n\n sourceUpdater.logger_(`Setting ${type}timestampOffset to ${offset}`);\n sourceBuffer.timestampOffset = offset;\n },\n callback: callback => (type, sourceUpdater) => {\n callback();\n },\n endOfStream: error => sourceUpdater => {\n if (sourceUpdater.mediaSource.readyState !== 'open') {\n return;\n }\n\n sourceUpdater.logger_(`Calling mediaSource endOfStream(${error || ''})`);\n\n try {\n sourceUpdater.mediaSource.endOfStream(error);\n } catch (e) {\n videojs.log.warn('Failed to call media source endOfStream', e);\n }\n },\n duration: duration => sourceUpdater => {\n sourceUpdater.logger_(`Setting mediaSource duration to ${duration}`);\n\n try {\n sourceUpdater.mediaSource.duration = duration;\n } catch (e) {\n videojs.log.warn('Failed to set media source duration', e);\n }\n },\n abort: () => (type, sourceUpdater) => {\n if (sourceUpdater.mediaSource.readyState !== 'open') {\n return;\n }\n\n const sourceBuffer = sourceUpdater[`${type}Buffer`]; // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n }\n\n sourceUpdater.logger_(`calling abort on ${type}Buffer`);\n\n try {\n sourceBuffer.abort();\n } catch (e) {\n videojs.log.warn(`Failed to abort on ${type}Buffer`, e);\n }\n },\n addSourceBuffer: (type, codec) => sourceUpdater => {\n const titleType = toTitleCase(type);\n const mime = getMimeForCodec(codec);\n sourceUpdater.logger_(`Adding ${type}Buffer with codec ${codec} to mediaSource`);\n const sourceBuffer = sourceUpdater.mediaSource.addSourceBuffer(mime);\n sourceBuffer.addEventListener('updateend', sourceUpdater[`on${titleType}UpdateEnd_`]);\n sourceBuffer.addEventListener('error', sourceUpdater[`on${titleType}Error_`]);\n sourceUpdater.codecs[type] = codec;\n sourceUpdater[`${type}Buffer`] = sourceBuffer;\n },\n removeSourceBuffer: type => sourceUpdater => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`];\n cleanupBuffer(type, sourceUpdater); // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n }\n\n sourceUpdater.logger_(`Removing ${type}Buffer with codec ${sourceUpdater.codecs[type]} from mediaSource`);\n\n try {\n sourceUpdater.mediaSource.removeSourceBuffer(sourceBuffer);\n } catch (e) {\n videojs.log.warn(`Failed to removeSourceBuffer ${type}Buffer`, e);\n }\n },\n changeType: codec => (type, sourceUpdater) => {\n const sourceBuffer = sourceUpdater[`${type}Buffer`];\n const mime = getMimeForCodec(codec); // can't do anything if the media source / source buffer is null\n // or the media source does not contain this source buffer.\n\n if (!inSourceBuffers(sourceUpdater.mediaSource, sourceBuffer)) {\n return;\n } // do not update codec if we don't need to.\n // Only update if we change the codec base.\n // For example, going from avc1.640028 to avc1.64001f does not require a changeType call.\n\n\n const newCodecBase = codec.substring(0, codec.indexOf('.'));\n const oldCodec = sourceUpdater.codecs[type];\n const oldCodecBase = oldCodec.substring(0, oldCodec.indexOf('.'));\n\n if (oldCodecBase === newCodecBase) {\n return;\n }\n\n const metadata = {\n codecsChangeInfo: {\n from: oldCodec,\n to: codec\n }\n };\n sourceUpdater.trigger({\n type: 'codecschange',\n metadata\n });\n sourceUpdater.logger_(`changing ${type}Buffer codec from ${oldCodec} to ${codec}`); // check if change to the provided type is supported\n\n try {\n sourceBuffer.changeType(mime);\n sourceUpdater.codecs[type] = codec;\n } catch (e) {\n metadata.errorType = videojs.Error.StreamingCodecsChangeError;\n metadata.error = e;\n e.metadata = metadata;\n sourceUpdater.error_ = e;\n sourceUpdater.trigger('error');\n videojs.log.warn(`Failed to changeType on ${type}Buffer`, e);\n }\n }\n};\n\nconst pushQueue = ({\n type,\n sourceUpdater,\n action,\n doneFn,\n name\n}) => {\n sourceUpdater.queue.push({\n type,\n action,\n doneFn,\n name\n });\n shiftQueue(type, sourceUpdater);\n};\n\nconst onUpdateend = (type, sourceUpdater) => e => {\n // Although there should, in theory, be a pending action for any updateend receieved,\n // there are some actions that may trigger updateend events without set definitions in\n // the w3c spec. For instance, setting the duration on the media source may trigger\n // updateend events on source buffers. This does not appear to be in the spec. As such,\n // if we encounter an updateend without a corresponding pending action from our queue\n // for that source buffer type, process the next action.\n const bufferedRangesForType = sourceUpdater[`${type}Buffered`]();\n const descriptiveString = bufferedRangesToString(bufferedRangesForType);\n sourceUpdater.logger_(`received \"updateend\" event for ${type} Source Buffer: `, descriptiveString);\n\n if (sourceUpdater.queuePending[type]) {\n const doneFn = sourceUpdater.queuePending[type].doneFn;\n sourceUpdater.queuePending[type] = null;\n\n if (doneFn) {\n // if there's an error, report it\n doneFn(sourceUpdater[`${type}Error_`]);\n }\n }\n\n shiftQueue(type, sourceUpdater);\n};\n/**\n * A queue of callbacks to be serialized and applied when a\n * MediaSource and its associated SourceBuffers are not in the\n * updating state. It is used by the segment loader to update the\n * underlying SourceBuffers when new data is loaded, for instance.\n *\n * @class SourceUpdater\n * @param {MediaSource} mediaSource the MediaSource to create the SourceBuffer from\n * @param {string} mimeType the desired MIME type of the underlying SourceBuffer\n */\n\n\nclass SourceUpdater extends videojs.EventTarget {\n constructor(mediaSource) {\n super();\n this.mediaSource = mediaSource;\n\n this.sourceopenListener_ = () => shiftQueue('mediaSource', this);\n\n this.mediaSource.addEventListener('sourceopen', this.sourceopenListener_);\n this.logger_ = logger('SourceUpdater'); // initial timestamp offset is 0\n\n this.audioTimestampOffset_ = 0;\n this.videoTimestampOffset_ = 0;\n this.queue = [];\n this.queuePending = {\n audio: null,\n video: null\n };\n this.delayedAudioAppendQueue_ = [];\n this.videoAppendQueued_ = false;\n this.codecs = {};\n this.onVideoUpdateEnd_ = onUpdateend('video', this);\n this.onAudioUpdateEnd_ = onUpdateend('audio', this);\n\n this.onVideoError_ = e => {\n // used for debugging\n this.videoError_ = e;\n };\n\n this.onAudioError_ = e => {\n // used for debugging\n this.audioError_ = e;\n };\n\n this.createdSourceBuffers_ = false;\n this.initializedEme_ = false;\n this.triggeredReady_ = false;\n }\n\n initializedEme() {\n this.initializedEme_ = true;\n this.triggerReady();\n }\n\n hasCreatedSourceBuffers() {\n // if false, likely waiting on one of the segment loaders to get enough data to create\n // source buffers\n return this.createdSourceBuffers_;\n }\n\n hasInitializedAnyEme() {\n return this.initializedEme_;\n }\n\n ready() {\n return this.hasCreatedSourceBuffers() && this.hasInitializedAnyEme();\n }\n\n createSourceBuffers(codecs) {\n if (this.hasCreatedSourceBuffers()) {\n // already created them before\n return;\n } // the intial addOrChangeSourceBuffers will always be\n // two add buffers.\n\n\n this.addOrChangeSourceBuffers(codecs);\n this.createdSourceBuffers_ = true;\n this.trigger('createdsourcebuffers');\n this.triggerReady();\n }\n\n triggerReady() {\n // only allow ready to be triggered once, this prevents the case\n // where:\n // 1. we trigger createdsourcebuffers\n // 2. ie 11 synchronously initializates eme\n // 3. the synchronous initialization causes us to trigger ready\n // 4. We go back to the ready check in createSourceBuffers and ready is triggered again.\n if (this.ready() && !this.triggeredReady_) {\n this.triggeredReady_ = true;\n this.trigger('ready');\n }\n }\n /**\n * Add a type of source buffer to the media source.\n *\n * @param {string} type\n * The type of source buffer to add.\n *\n * @param {string} codec\n * The codec to add the source buffer with.\n */\n\n\n addSourceBuffer(type, codec) {\n pushQueue({\n type: 'mediaSource',\n sourceUpdater: this,\n action: actions.addSourceBuffer(type, codec),\n name: 'addSourceBuffer'\n });\n }\n /**\n * call abort on a source buffer.\n *\n * @param {string} type\n * The type of source buffer to call abort on.\n */\n\n\n abort(type) {\n pushQueue({\n type,\n sourceUpdater: this,\n action: actions.abort(type),\n name: 'abort'\n });\n }\n /**\n * Call removeSourceBuffer and remove a specific type\n * of source buffer on the mediaSource.\n *\n * @param {string} type\n * The type of source buffer to remove.\n */\n\n\n removeSourceBuffer(type) {\n if (!this.canRemoveSourceBuffer()) {\n videojs.log.error('removeSourceBuffer is not supported!');\n return;\n }\n\n pushQueue({\n type: 'mediaSource',\n sourceUpdater: this,\n action: actions.removeSourceBuffer(type),\n name: 'removeSourceBuffer'\n });\n }\n /**\n * Whether or not the removeSourceBuffer function is supported\n * on the mediaSource.\n *\n * @return {boolean}\n * if removeSourceBuffer can be called.\n */\n\n\n canRemoveSourceBuffer() {\n // As of Firefox 83 removeSourceBuffer\n // throws errors, so we report that it does not support this.\n return !videojs.browser.IS_FIREFOX && window$1.MediaSource && window$1.MediaSource.prototype && typeof window$1.MediaSource.prototype.removeSourceBuffer === 'function';\n }\n /**\n * Whether or not the changeType function is supported\n * on our SourceBuffers.\n *\n * @return {boolean}\n * if changeType can be called.\n */\n\n\n static canChangeType() {\n return window$1.SourceBuffer && window$1.SourceBuffer.prototype && typeof window$1.SourceBuffer.prototype.changeType === 'function';\n }\n /**\n * Whether or not the changeType function is supported\n * on our SourceBuffers.\n *\n * @return {boolean}\n * if changeType can be called.\n */\n\n\n canChangeType() {\n return this.constructor.canChangeType();\n }\n /**\n * Call the changeType function on a source buffer, given the code and type.\n *\n * @param {string} type\n * The type of source buffer to call changeType on.\n *\n * @param {string} codec\n * The codec string to change type with on the source buffer.\n */\n\n\n changeType(type, codec) {\n if (!this.canChangeType()) {\n videojs.log.error('changeType is not supported!');\n return;\n }\n\n pushQueue({\n type,\n sourceUpdater: this,\n action: actions.changeType(codec),\n name: 'changeType'\n });\n }\n /**\n * Add source buffers with a codec or, if they are already created,\n * call changeType on source buffers using changeType.\n *\n * @param {Object} codecs\n * Codecs to switch to\n */\n\n\n addOrChangeSourceBuffers(codecs) {\n if (!codecs || typeof codecs !== 'object' || Object.keys(codecs).length === 0) {\n throw new Error('Cannot addOrChangeSourceBuffers to undefined codecs');\n }\n\n Object.keys(codecs).forEach(type => {\n const codec = codecs[type];\n\n if (!this.hasCreatedSourceBuffers()) {\n return this.addSourceBuffer(type, codec);\n }\n\n if (this.canChangeType()) {\n this.changeType(type, codec);\n }\n });\n }\n /**\n * Queue an update to append an ArrayBuffer.\n *\n * @param {MediaObject} object containing audioBytes and/or videoBytes\n * @param {Function} done the function to call when done\n * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendBuffer-void-ArrayBuffer-data\n */\n\n\n appendBuffer(options, doneFn) {\n const {\n segmentInfo,\n type,\n bytes\n } = options;\n this.processedAppend_ = true;\n\n if (type === 'audio' && this.videoBuffer && !this.videoAppendQueued_) {\n this.delayedAudioAppendQueue_.push([options, doneFn]);\n this.logger_(`delayed audio append of ${bytes.length} until video append`);\n return;\n } // In the case of certain errors, for instance, QUOTA_EXCEEDED_ERR, updateend will\n // not be fired. This means that the queue will be blocked until the next action\n // taken by the segment-loader. Provide a mechanism for segment-loader to handle\n // these errors by calling the doneFn with the specific error.\n\n\n const onError = doneFn;\n pushQueue({\n type,\n sourceUpdater: this,\n action: actions.appendBuffer(bytes, segmentInfo || {\n mediaIndex: -1\n }, onError),\n doneFn,\n name: 'appendBuffer'\n });\n\n if (type === 'video') {\n this.videoAppendQueued_ = true;\n\n if (!this.delayedAudioAppendQueue_.length) {\n return;\n }\n\n const queue = this.delayedAudioAppendQueue_.slice();\n this.logger_(`queuing delayed audio ${queue.length} appendBuffers`);\n this.delayedAudioAppendQueue_.length = 0;\n queue.forEach(que => {\n this.appendBuffer.apply(this, que);\n });\n }\n }\n /**\n * Get the audio buffer's buffered timerange.\n *\n * @return {TimeRange}\n * The audio buffer's buffered time range\n */\n\n\n audioBuffered() {\n // no media source/source buffer or it isn't in the media sources\n // source buffer list\n if (!inSourceBuffers(this.mediaSource, this.audioBuffer)) {\n return createTimeRanges();\n }\n\n return this.audioBuffer.buffered ? this.audioBuffer.buffered : createTimeRanges();\n }\n /**\n * Get the video buffer's buffered timerange.\n *\n * @return {TimeRange}\n * The video buffer's buffered time range\n */\n\n\n videoBuffered() {\n // no media source/source buffer or it isn't in the media sources\n // source buffer list\n if (!inSourceBuffers(this.mediaSource, this.videoBuffer)) {\n return createTimeRanges();\n }\n\n return this.videoBuffer.buffered ? this.videoBuffer.buffered : createTimeRanges();\n }\n /**\n * Get a combined video/audio buffer's buffered timerange.\n *\n * @return {TimeRange}\n * the combined time range\n */\n\n\n buffered() {\n const video = inSourceBuffers(this.mediaSource, this.videoBuffer) ? this.videoBuffer : null;\n const audio = inSourceBuffers(this.mediaSource, this.audioBuffer) ? this.audioBuffer : null;\n\n if (audio && !video) {\n return this.audioBuffered();\n }\n\n if (video && !audio) {\n return this.videoBuffered();\n }\n\n return bufferIntersection(this.audioBuffered(), this.videoBuffered());\n }\n /**\n * Add a callback to the queue that will set duration on the mediaSource.\n *\n * @param {number} duration\n * The duration to set\n *\n * @param {Function} [doneFn]\n * function to run after duration has been set.\n */\n\n\n setDuration(duration, doneFn = noop) {\n // In order to set the duration on the media source, it's necessary to wait for all\n // source buffers to no longer be updating. \"If the updating attribute equals true on\n // any SourceBuffer in sourceBuffers, then throw an InvalidStateError exception and\n // abort these steps.\" (source: https://www.w3.org/TR/media-source/#attributes).\n pushQueue({\n type: 'mediaSource',\n sourceUpdater: this,\n action: actions.duration(duration),\n name: 'duration',\n doneFn\n });\n }\n /**\n * Add a mediaSource endOfStream call to the queue\n *\n * @param {Error} [error]\n * Call endOfStream with an error\n *\n * @param {Function} [doneFn]\n * A function that should be called when the\n * endOfStream call has finished.\n */\n\n\n endOfStream(error = null, doneFn = noop) {\n if (typeof error !== 'string') {\n error = undefined;\n } // In order to set the duration on the media source, it's necessary to wait for all\n // source buffers to no longer be updating. \"If the updating attribute equals true on\n // any SourceBuffer in sourceBuffers, then throw an InvalidStateError exception and\n // abort these steps.\" (source: https://www.w3.org/TR/media-source/#attributes).\n\n\n pushQueue({\n type: 'mediaSource',\n sourceUpdater: this,\n action: actions.endOfStream(error),\n name: 'endOfStream',\n doneFn\n });\n }\n /**\n * Queue an update to remove a time range from the buffer.\n *\n * @param {number} start where to start the removal\n * @param {number} end where to end the removal\n * @param {Function} [done=noop] optional callback to be executed when the remove\n * operation is complete\n * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-remove-void-double-start-unrestricted-double-end\n */\n\n\n removeAudio(start, end, done = noop) {\n if (!this.audioBuffered().length || this.audioBuffered().end(0) === 0) {\n done();\n return;\n }\n\n pushQueue({\n type: 'audio',\n sourceUpdater: this,\n action: actions.remove(start, end),\n doneFn: done,\n name: 'remove'\n });\n }\n /**\n * Queue an update to remove a time range from the buffer.\n *\n * @param {number} start where to start the removal\n * @param {number} end where to end the removal\n * @param {Function} [done=noop] optional callback to be executed when the remove\n * operation is complete\n * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-remove-void-double-start-unrestricted-double-end\n */\n\n\n removeVideo(start, end, done = noop) {\n if (!this.videoBuffered().length || this.videoBuffered().end(0) === 0) {\n done();\n return;\n }\n\n pushQueue({\n type: 'video',\n sourceUpdater: this,\n action: actions.remove(start, end),\n doneFn: done,\n name: 'remove'\n });\n }\n /**\n * Whether the underlying sourceBuffer is updating or not\n *\n * @return {boolean} the updating status of the SourceBuffer\n */\n\n\n updating() {\n // the audio/video source buffer is updating\n if (updating('audio', this) || updating('video', this)) {\n return true;\n }\n\n return false;\n }\n /**\n * Set/get the timestampoffset on the audio SourceBuffer\n *\n * @return {number} the timestamp offset\n */\n\n\n audioTimestampOffset(offset) {\n if (typeof offset !== 'undefined' && this.audioBuffer && // no point in updating if it's the same\n this.audioTimestampOffset_ !== offset) {\n pushQueue({\n type: 'audio',\n sourceUpdater: this,\n action: actions.timestampOffset(offset),\n name: 'timestampOffset'\n });\n this.audioTimestampOffset_ = offset;\n }\n\n return this.audioTimestampOffset_;\n }\n /**\n * Set/get the timestampoffset on the video SourceBuffer\n *\n * @return {number} the timestamp offset\n */\n\n\n videoTimestampOffset(offset) {\n if (typeof offset !== 'undefined' && this.videoBuffer && // no point in updating if it's the same\n this.videoTimestampOffset_ !== offset) {\n pushQueue({\n type: 'video',\n sourceUpdater: this,\n action: actions.timestampOffset(offset),\n name: 'timestampOffset'\n });\n this.videoTimestampOffset_ = offset;\n }\n\n return this.videoTimestampOffset_;\n }\n /**\n * Add a function to the queue that will be called\n * when it is its turn to run in the audio queue.\n *\n * @param {Function} callback\n * The callback to queue.\n */\n\n\n audioQueueCallback(callback) {\n if (!this.audioBuffer) {\n return;\n }\n\n pushQueue({\n type: 'audio',\n sourceUpdater: this,\n action: actions.callback(callback),\n name: 'callback'\n });\n }\n /**\n * Add a function to the queue that will be called\n * when it is its turn to run in the video queue.\n *\n * @param {Function} callback\n * The callback to queue.\n */\n\n\n videoQueueCallback(callback) {\n if (!this.videoBuffer) {\n return;\n }\n\n pushQueue({\n type: 'video',\n sourceUpdater: this,\n action: actions.callback(callback),\n name: 'callback'\n });\n }\n /**\n * dispose of the source updater and the underlying sourceBuffer\n */\n\n\n dispose() {\n this.trigger('dispose');\n bufferTypes.forEach(type => {\n this.abort(type);\n\n if (this.canRemoveSourceBuffer()) {\n this.removeSourceBuffer(type);\n } else {\n this[`${type}QueueCallback`](() => cleanupBuffer(type, this));\n }\n });\n this.videoAppendQueued_ = false;\n this.delayedAudioAppendQueue_.length = 0;\n\n if (this.sourceopenListener_) {\n this.mediaSource.removeEventListener('sourceopen', this.sourceopenListener_);\n }\n\n this.off();\n }\n\n}\n\nconst uint8ToUtf8 = uintArray => decodeURIComponent(escape(String.fromCharCode.apply(null, uintArray)));\nconst bufferToHexString = buffer => {\n const uInt8Buffer = new Uint8Array(buffer);\n return Array.from(uInt8Buffer).map(byte => byte.toString(16).padStart(2, '0')).join('');\n};\n\n/**\n * @file vtt-segment-loader.js\n */\nconst VTT_LINE_TERMINATORS = new Uint8Array('\\n\\n'.split('').map(char => char.charCodeAt(0)));\n\nclass NoVttJsError extends Error {\n constructor() {\n super('Trying to parse received VTT cues, but there is no WebVTT. Make sure vtt.js is loaded.');\n }\n\n}\n/**\n * An object that manages segment loading and appending.\n *\n * @class VTTSegmentLoader\n * @param {Object} options required and optional options\n * @extends videojs.EventTarget\n */\n\n\nclass VTTSegmentLoader extends SegmentLoader {\n constructor(settings, options = {}) {\n super(settings, options); // SegmentLoader requires a MediaSource be specified or it will throw an error;\n // however, VTTSegmentLoader has no need of a media source, so delete the reference\n\n this.mediaSource_ = null;\n this.subtitlesTrack_ = null;\n this.featuresNativeTextTracks_ = settings.featuresNativeTextTracks;\n this.loadVttJs = settings.loadVttJs; // The VTT segment will have its own time mappings. Saving VTT segment timing info in\n // the sync controller leads to improper behavior.\n\n this.shouldSaveSegmentTimingInfo_ = false;\n }\n /**\n * Indicates which time ranges are buffered\n *\n * @return {TimeRange}\n * TimeRange object representing the current buffered ranges\n */\n\n\n buffered_() {\n if (!this.subtitlesTrack_ || !this.subtitlesTrack_.cues || !this.subtitlesTrack_.cues.length) {\n return createTimeRanges();\n }\n\n const cues = this.subtitlesTrack_.cues;\n const start = cues[0].startTime;\n const end = cues[cues.length - 1].startTime;\n return createTimeRanges([[start, end]]);\n }\n /**\n * Gets and sets init segment for the provided map\n *\n * @param {Object} map\n * The map object representing the init segment to get or set\n * @param {boolean=} set\n * If true, the init segment for the provided map should be saved\n * @return {Object}\n * map object for desired init segment\n */\n\n\n initSegmentForMap(map, set = false) {\n if (!map) {\n return null;\n }\n\n const id = initSegmentId(map);\n let storedMap = this.initSegments_[id];\n\n if (set && !storedMap && map.bytes) {\n // append WebVTT line terminators to the media initialization segment if it exists\n // to follow the WebVTT spec (https://w3c.github.io/webvtt/#file-structure) that\n // requires two or more WebVTT line terminators between the WebVTT header and the\n // rest of the file\n const combinedByteLength = VTT_LINE_TERMINATORS.byteLength + map.bytes.byteLength;\n const combinedSegment = new Uint8Array(combinedByteLength);\n combinedSegment.set(map.bytes);\n combinedSegment.set(VTT_LINE_TERMINATORS, map.bytes.byteLength);\n this.initSegments_[id] = storedMap = {\n resolvedUri: map.resolvedUri,\n byterange: map.byterange,\n bytes: combinedSegment\n };\n }\n\n return storedMap || map;\n }\n /**\n * Returns true if all configuration required for loading is present, otherwise false.\n *\n * @return {boolean} True if the all configuration is ready for loading\n * @private\n */\n\n\n couldBeginLoading_() {\n return this.playlist_ && this.subtitlesTrack_ && !this.paused();\n }\n /**\n * Once all the starting parameters have been specified, begin\n * operation. This method should only be invoked from the INIT\n * state.\n *\n * @private\n */\n\n\n init_() {\n this.state = 'READY';\n this.resetEverything();\n return this.monitorBuffer_();\n }\n /**\n * Set a subtitle track on the segment loader to add subtitles to\n *\n * @param {TextTrack=} track\n * The text track to add loaded subtitles to\n * @return {TextTrack}\n * Returns the subtitles track\n */\n\n\n track(track) {\n if (typeof track === 'undefined') {\n return this.subtitlesTrack_;\n }\n\n this.subtitlesTrack_ = track; // if we were unpaused but waiting for a sourceUpdater, start\n // buffering now\n\n if (this.state === 'INIT' && this.couldBeginLoading_()) {\n this.init_();\n }\n\n return this.subtitlesTrack_;\n }\n /**\n * Remove any data in the source buffer between start and end times\n *\n * @param {number} start - the start time of the region to remove from the buffer\n * @param {number} end - the end time of the region to remove from the buffer\n */\n\n\n remove(start, end) {\n removeCuesFromTrack(start, end, this.subtitlesTrack_);\n }\n /**\n * fill the buffer with segements unless the sourceBuffers are\n * currently updating\n *\n * Note: this function should only ever be called by monitorBuffer_\n * and never directly\n *\n * @private\n */\n\n\n fillBuffer_() {\n // see if we need to begin loading immediately\n const segmentInfo = this.chooseNextRequest_();\n\n if (!segmentInfo) {\n return;\n }\n\n if (this.syncController_.timestampOffsetForTimeline(segmentInfo.timeline) === null) {\n // We don't have the timestamp offset that we need to sync subtitles.\n // Rerun on a timestamp offset or user interaction.\n const checkTimestampOffset = () => {\n this.state = 'READY';\n\n if (!this.paused()) {\n // if not paused, queue a buffer check as soon as possible\n this.monitorBuffer_();\n }\n };\n\n this.syncController_.one('timestampoffset', checkTimestampOffset);\n this.state = 'WAITING_ON_TIMELINE';\n return;\n }\n\n this.loadSegment_(segmentInfo);\n } // never set a timestamp offset for vtt segments.\n\n\n timestampOffsetForSegment_() {\n return null;\n }\n\n chooseNextRequest_() {\n return this.skipEmptySegments_(super.chooseNextRequest_());\n }\n /**\n * Prevents the segment loader from requesting segments we know contain no subtitles\n * by walking forward until we find the next segment that we don't know whether it is\n * empty or not.\n *\n * @param {Object} segmentInfo\n * a segment info object that describes the current segment\n * @return {Object}\n * a segment info object that describes the current segment\n */\n\n\n skipEmptySegments_(segmentInfo) {\n while (segmentInfo && segmentInfo.segment.empty) {\n // stop at the last possible segmentInfo\n if (segmentInfo.mediaIndex + 1 >= segmentInfo.playlist.segments.length) {\n segmentInfo = null;\n break;\n }\n\n segmentInfo = this.generateSegmentInfo_({\n playlist: segmentInfo.playlist,\n mediaIndex: segmentInfo.mediaIndex + 1,\n startOfSegment: segmentInfo.startOfSegment + segmentInfo.duration,\n isSyncRequest: segmentInfo.isSyncRequest\n });\n }\n\n return segmentInfo;\n }\n\n stopForError(error) {\n this.error(error);\n this.state = 'READY';\n this.pause();\n this.trigger('error');\n }\n /**\n * append a decrypted segement to the SourceBuffer through a SourceUpdater\n *\n * @private\n */\n\n\n segmentRequestFinished_(error, simpleSegment, result) {\n if (!this.subtitlesTrack_) {\n this.state = 'READY';\n return;\n }\n\n this.saveTransferStats_(simpleSegment.stats); // the request was aborted\n\n if (!this.pendingSegment_) {\n this.state = 'READY';\n this.mediaRequestsAborted += 1;\n return;\n }\n\n if (error) {\n if (error.code === REQUEST_ERRORS.TIMEOUT) {\n this.handleTimeout_();\n }\n\n if (error.code === REQUEST_ERRORS.ABORTED) {\n this.mediaRequestsAborted += 1;\n } else {\n this.mediaRequestsErrored += 1;\n }\n\n this.stopForError(error);\n return;\n }\n\n const segmentInfo = this.pendingSegment_;\n const isMp4WebVttSegmentWithCues = result.mp4VttCues && result.mp4VttCues.length;\n\n if (isMp4WebVttSegmentWithCues) {\n segmentInfo.mp4VttCues = result.mp4VttCues;\n } // although the VTT segment loader bandwidth isn't really used, it's good to\n // maintain functionality between segment loaders\n\n\n this.saveBandwidthRelatedStats_(segmentInfo.duration, simpleSegment.stats); // if this request included a segment key, save that data in the cache\n\n if (simpleSegment.key) {\n this.segmentKey(simpleSegment.key, true);\n }\n\n this.state = 'APPENDING'; // used for tests\n\n this.trigger('appending');\n const segment = segmentInfo.segment;\n\n if (segment.map) {\n segment.map.bytes = simpleSegment.map.bytes;\n }\n\n segmentInfo.bytes = simpleSegment.bytes; // Make sure that vttjs has loaded, otherwise, load it and wait till it finished loading\n\n if (typeof window$1.WebVTT !== 'function' && typeof this.loadVttJs === 'function') {\n this.state = 'WAITING_ON_VTTJS'; // should be fine to call multiple times\n // script will be loaded once but multiple listeners will be added to the queue, which is expected.\n\n this.loadVttJs().then(() => this.segmentRequestFinished_(error, simpleSegment, result), () => this.stopForError({\n message: 'Error loading vtt.js'\n }));\n return;\n }\n\n segment.requested = true;\n\n try {\n this.parseVTTCues_(segmentInfo);\n } catch (e) {\n this.stopForError({\n message: e.message,\n metadata: {\n errorType: videojs.Error.StreamingVttParserError,\n error: e\n }\n });\n return;\n }\n\n if (!isMp4WebVttSegmentWithCues) {\n this.updateTimeMapping_(segmentInfo, this.syncController_.timelines[segmentInfo.timeline], this.playlist_);\n }\n\n if (segmentInfo.cues.length) {\n segmentInfo.timingInfo = {\n start: segmentInfo.cues[0].startTime,\n end: segmentInfo.cues[segmentInfo.cues.length - 1].endTime\n };\n } else {\n segmentInfo.timingInfo = {\n start: segmentInfo.startOfSegment,\n end: segmentInfo.startOfSegment + segmentInfo.duration\n };\n }\n\n if (segmentInfo.isSyncRequest) {\n this.trigger('syncinfoupdate');\n this.pendingSegment_ = null;\n this.state = 'READY';\n return;\n }\n\n segmentInfo.byteLength = segmentInfo.bytes.byteLength;\n this.mediaSecondsLoaded += segment.duration; // Create VTTCue instances for each cue in the new segment and add them to\n // the subtitle track\n\n segmentInfo.cues.forEach(cue => {\n this.subtitlesTrack_.addCue(this.featuresNativeTextTracks_ ? new window$1.VTTCue(cue.startTime, cue.endTime, cue.text) : cue);\n }); // Remove any duplicate cues from the subtitle track. The WebVTT spec allows\n // cues to have identical time-intervals, but if the text is also identical\n // we can safely assume it is a duplicate that can be removed (ex. when a cue\n // \"overlaps\" VTT segments)\n\n removeDuplicateCuesFromTrack(this.subtitlesTrack_);\n this.handleAppendsDone_();\n }\n\n handleData_(simpleSegment, result) {\n const isVttType = simpleSegment && simpleSegment.type === 'vtt';\n const isTextResult = result && result.type === 'text';\n const isFmp4VttSegment = isVttType && isTextResult; // handle segment data for fmp4 encapsulated webvtt\n\n if (isFmp4VttSegment) {\n super.handleData_(simpleSegment, result);\n }\n }\n\n updateTimingInfoEnd_() {// noop\n }\n /**\n * Utility function for converting mp4 webvtt cue objects into VTTCues.\n *\n * @param {Object} segmentInfo with mp4 webvtt cues for parsing into VTTCue objecs\n */\n\n\n parseMp4VttCues_(segmentInfo) {\n const timestampOffset = this.sourceUpdater_.videoTimestampOffset() === null ? this.sourceUpdater_.audioTimestampOffset() : this.sourceUpdater_.videoTimestampOffset();\n segmentInfo.mp4VttCues.forEach(cue => {\n const start = cue.start + timestampOffset;\n const end = cue.end + timestampOffset;\n const vttCue = new window$1.VTTCue(start, end, cue.cueText);\n\n if (cue.settings) {\n cue.settings.split(' ').forEach(cueSetting => {\n const keyValString = cueSetting.split(':');\n const key = keyValString[0];\n const value = keyValString[1];\n vttCue[key] = isNaN(value) ? value : Number(value);\n });\n }\n\n segmentInfo.cues.push(vttCue);\n });\n }\n /**\n * Uses the WebVTT parser to parse the segment response\n *\n * @throws NoVttJsError\n *\n * @param {Object} segmentInfo\n * a segment info object that describes the current segment\n * @private\n */\n\n\n parseVTTCues_(segmentInfo) {\n let decoder;\n let decodeBytesToString = false;\n\n if (typeof window$1.WebVTT !== 'function') {\n // caller is responsible for exception handling.\n throw new NoVttJsError();\n }\n\n segmentInfo.cues = [];\n segmentInfo.timestampmap = {\n MPEGTS: 0,\n LOCAL: 0\n };\n\n if (segmentInfo.mp4VttCues) {\n this.parseMp4VttCues_(segmentInfo);\n return;\n }\n\n if (typeof window$1.TextDecoder === 'function') {\n decoder = new window$1.TextDecoder('utf8');\n } else {\n decoder = window$1.WebVTT.StringDecoder();\n decodeBytesToString = true;\n }\n\n const parser = new window$1.WebVTT.Parser(window$1, window$1.vttjs, decoder);\n parser.oncue = segmentInfo.cues.push.bind(segmentInfo.cues);\n\n parser.ontimestampmap = map => {\n segmentInfo.timestampmap = map;\n };\n\n parser.onparsingerror = error => {\n videojs.log.warn('Error encountered when parsing cues: ' + error.message);\n };\n\n if (segmentInfo.segment.map) {\n let mapData = segmentInfo.segment.map.bytes;\n\n if (decodeBytesToString) {\n mapData = uint8ToUtf8(mapData);\n }\n\n parser.parse(mapData);\n }\n\n let segmentData = segmentInfo.bytes;\n\n if (decodeBytesToString) {\n segmentData = uint8ToUtf8(segmentData);\n }\n\n parser.parse(segmentData);\n parser.flush();\n }\n /**\n * Updates the start and end times of any cues parsed by the WebVTT parser using\n * the information parsed from the X-TIMESTAMP-MAP header and a TS to media time mapping\n * from the SyncController\n *\n * @param {Object} segmentInfo\n * a segment info object that describes the current segment\n * @param {Object} mappingObj\n * object containing a mapping from TS to media time\n * @param {Object} playlist\n * the playlist object containing the segment\n * @private\n */\n\n\n updateTimeMapping_(segmentInfo, mappingObj, playlist) {\n const segment = segmentInfo.segment;\n\n if (!mappingObj) {\n // If the sync controller does not have a mapping of TS to Media Time for the\n // timeline, then we don't have enough information to update the cue\n // start/end times\n return;\n }\n\n if (!segmentInfo.cues.length) {\n // If there are no cues, we also do not have enough information to figure out\n // segment timing. Mark that the segment contains no cues so we don't re-request\n // an empty segment.\n segment.empty = true;\n return;\n }\n\n const {\n MPEGTS,\n LOCAL\n } = segmentInfo.timestampmap;\n /**\n * From the spec:\n * The MPEGTS media timestamp MUST use a 90KHz timescale,\n * even when non-WebVTT Media Segments use a different timescale.\n */\n\n const mpegTsInSeconds = MPEGTS / ONE_SECOND_IN_TS;\n const diff = mpegTsInSeconds - LOCAL + mappingObj.mapping;\n segmentInfo.cues.forEach(cue => {\n const duration = cue.endTime - cue.startTime;\n const startTime = this.handleRollover_(cue.startTime + diff, mappingObj.time);\n cue.startTime = Math.max(startTime, 0);\n cue.endTime = Math.max(startTime + duration, 0);\n });\n\n if (!playlist.syncInfo) {\n const firstStart = segmentInfo.cues[0].startTime;\n const lastStart = segmentInfo.cues[segmentInfo.cues.length - 1].startTime;\n playlist.syncInfo = {\n mediaSequence: playlist.mediaSequence + segmentInfo.mediaIndex,\n time: Math.min(firstStart, lastStart - segment.duration)\n };\n }\n }\n /**\n * MPEG-TS PES timestamps are limited to 2^33.\n * Once they reach 2^33, they roll over to 0.\n * mux.js handles PES timestamp rollover for the following scenarios:\n * [forward rollover(right)] ->\n * PES timestamps monotonically increase, and once they reach 2^33, they roll over to 0\n * [backward rollover(left)] -->\n * we seek back to position before rollover.\n *\n * According to the HLS SPEC:\n * When synchronizing WebVTT with PES timestamps, clients SHOULD account\n * for cases where the 33-bit PES timestamps have wrapped and the WebVTT\n * cue times have not. When the PES timestamp wraps, the WebVTT Segment\n * SHOULD have a X-TIMESTAMP-MAP header that maps the current WebVTT\n * time to the new (low valued) PES timestamp.\n *\n * So we want to handle rollover here and align VTT Cue start/end time to the player's time.\n */\n\n\n handleRollover_(value, reference) {\n if (reference === null) {\n return value;\n }\n\n let valueIn90khz = value * ONE_SECOND_IN_TS;\n const referenceIn90khz = reference * ONE_SECOND_IN_TS;\n let offset;\n\n if (referenceIn90khz < valueIn90khz) {\n // - 2^33\n offset = -8589934592;\n } else {\n // + 2^33\n offset = 8589934592;\n } // distance(value - reference) > 2^32\n\n\n while (Math.abs(valueIn90khz - referenceIn90khz) > 4294967296) {\n valueIn90khz += offset;\n }\n\n return valueIn90khz / ONE_SECOND_IN_TS;\n }\n\n}\n\n/**\n * @file ad-cue-tags.js\n */\n/**\n * Searches for an ad cue that overlaps with the given mediaTime\n *\n * @param {Object} track\n * the track to find the cue for\n *\n * @param {number} mediaTime\n * the time to find the cue at\n *\n * @return {Object|null}\n * the found cue or null\n */\n\nconst findAdCue = function (track, mediaTime) {\n const cues = track.cues;\n\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n\n if (mediaTime >= cue.adStartTime && mediaTime <= cue.adEndTime) {\n return cue;\n }\n }\n\n return null;\n};\nconst updateAdCues = function (media, track, offset = 0) {\n if (!media.segments) {\n return;\n }\n\n let mediaTime = offset;\n let cue;\n\n for (let i = 0; i < media.segments.length; i++) {\n const segment = media.segments[i];\n\n if (!cue) {\n // Since the cues will span for at least the segment duration, adding a fudge\n // factor of half segment duration will prevent duplicate cues from being\n // created when timing info is not exact (e.g. cue start time initialized\n // at 10.006677, but next call mediaTime is 10.003332 )\n cue = findAdCue(track, mediaTime + segment.duration / 2);\n }\n\n if (cue) {\n if ('cueIn' in segment) {\n // Found a CUE-IN so end the cue\n cue.endTime = mediaTime;\n cue.adEndTime = mediaTime;\n mediaTime += segment.duration;\n cue = null;\n continue;\n }\n\n if (mediaTime < cue.endTime) {\n // Already processed this mediaTime for this cue\n mediaTime += segment.duration;\n continue;\n } // otherwise extend cue until a CUE-IN is found\n\n\n cue.endTime += segment.duration;\n } else {\n if ('cueOut' in segment) {\n cue = new window$1.VTTCue(mediaTime, mediaTime + segment.duration, segment.cueOut);\n cue.adStartTime = mediaTime; // Assumes tag format to be\n // #EXT-X-CUE-OUT:30\n\n cue.adEndTime = mediaTime + parseFloat(segment.cueOut);\n track.addCue(cue);\n }\n\n if ('cueOutCont' in segment) {\n // Entered into the middle of an ad cue\n // Assumes tag formate to be\n // #EXT-X-CUE-OUT-CONT:10/30\n const [adOffset, adTotal] = segment.cueOutCont.split('/').map(parseFloat);\n cue = new window$1.VTTCue(mediaTime, mediaTime + segment.duration, '');\n cue.adStartTime = mediaTime - adOffset;\n cue.adEndTime = cue.adStartTime + adTotal;\n track.addCue(cue);\n }\n }\n\n mediaTime += segment.duration;\n }\n};\n\nclass SyncInfo {\n /**\n * @param {number} start - media sequence start\n * @param {number} end - media sequence end\n * @param {number} segmentIndex - index for associated segment\n * @param {number|null} [partIndex] - index for associated part\n * @param {boolean} [appended] - appended indicator\n *\n */\n constructor({\n start,\n end,\n segmentIndex,\n partIndex = null,\n appended = false\n }) {\n this.start_ = start;\n this.end_ = end;\n this.segmentIndex_ = segmentIndex;\n this.partIndex_ = partIndex;\n this.appended_ = appended;\n }\n\n isInRange(targetTime) {\n return targetTime >= this.start && targetTime < this.end;\n }\n\n markAppended() {\n this.appended_ = true;\n }\n\n resetAppendedStatus() {\n this.appended_ = false;\n }\n\n get isAppended() {\n return this.appended_;\n }\n\n get start() {\n return this.start_;\n }\n\n get end() {\n return this.end_;\n }\n\n get segmentIndex() {\n return this.segmentIndex_;\n }\n\n get partIndex() {\n return this.partIndex_;\n }\n\n}\n\nclass SyncInfoData {\n /**\n *\n * @param {SyncInfo} segmentSyncInfo - sync info for a given segment\n * @param {Array} [partsSyncInfo] - sync infos for a list of parts for a given segment\n */\n constructor(segmentSyncInfo, partsSyncInfo = []) {\n this.segmentSyncInfo_ = segmentSyncInfo;\n this.partsSyncInfo_ = partsSyncInfo;\n }\n\n get segmentSyncInfo() {\n return this.segmentSyncInfo_;\n }\n\n get partsSyncInfo() {\n return this.partsSyncInfo_;\n }\n\n get hasPartsSyncInfo() {\n return this.partsSyncInfo_.length > 0;\n }\n\n resetAppendStatus() {\n this.segmentSyncInfo_.resetAppendedStatus();\n this.partsSyncInfo_.forEach(partSyncInfo => partSyncInfo.resetAppendedStatus());\n }\n\n}\n\nclass MediaSequenceSync {\n constructor() {\n /**\n * @type {Map}\n * @protected\n */\n this.storage_ = new Map();\n this.diagnostics_ = '';\n this.isReliable_ = false;\n this.start_ = -Infinity;\n this.end_ = Infinity;\n }\n\n get start() {\n return this.start_;\n }\n\n get end() {\n return this.end_;\n }\n\n get diagnostics() {\n return this.diagnostics_;\n }\n\n get isReliable() {\n return this.isReliable_;\n }\n\n resetAppendedStatus() {\n this.storage_.forEach(syncInfoData => syncInfoData.resetAppendStatus());\n }\n /**\n * update sync storage\n *\n * @param {Object} playlist\n * @param {number} currentTime\n *\n * @return {void}\n */\n\n\n update(playlist, currentTime) {\n const {\n mediaSequence,\n segments\n } = playlist;\n this.isReliable_ = this.isReliablePlaylist_(mediaSequence, segments);\n\n if (!this.isReliable_) {\n return;\n }\n\n return this.updateStorage_(segments, mediaSequence, this.calculateBaseTime_(mediaSequence, segments, currentTime));\n }\n /**\n * @param {number} targetTime\n * @return {SyncInfo|null}\n */\n\n\n getSyncInfoForTime(targetTime) {\n for (const {\n segmentSyncInfo,\n partsSyncInfo\n } of this.storage_.values()) {\n // Normal segment flow:\n if (!partsSyncInfo.length) {\n if (segmentSyncInfo.isInRange(targetTime)) {\n return segmentSyncInfo;\n }\n } else {\n // Low latency flow:\n for (const partSyncInfo of partsSyncInfo) {\n if (partSyncInfo.isInRange(targetTime)) {\n return partSyncInfo;\n }\n }\n }\n }\n\n return null;\n }\n\n getSyncInfoForMediaSequence(mediaSequence) {\n return this.storage_.get(mediaSequence);\n }\n\n updateStorage_(segments, startingMediaSequence, startingTime) {\n const newStorage = new Map();\n let newDiagnostics = '\\n';\n let currentStart = startingTime;\n let currentMediaSequence = startingMediaSequence;\n this.start_ = currentStart;\n segments.forEach((segment, segmentIndex) => {\n const prevSyncInfoData = this.storage_.get(currentMediaSequence);\n const segmentStart = currentStart;\n const segmentEnd = segmentStart + segment.duration;\n const segmentIsAppended = Boolean(prevSyncInfoData && prevSyncInfoData.segmentSyncInfo && prevSyncInfoData.segmentSyncInfo.isAppended);\n const segmentSyncInfo = new SyncInfo({\n start: segmentStart,\n end: segmentEnd,\n appended: segmentIsAppended,\n segmentIndex\n });\n segment.syncInfo = segmentSyncInfo;\n let currentPartStart = currentStart;\n const partsSyncInfo = (segment.parts || []).map((part, partIndex) => {\n const partStart = currentPartStart;\n const partEnd = currentPartStart + part.duration;\n const partIsAppended = Boolean(prevSyncInfoData && prevSyncInfoData.partsSyncInfo && prevSyncInfoData.partsSyncInfo[partIndex] && prevSyncInfoData.partsSyncInfo[partIndex].isAppended);\n const partSyncInfo = new SyncInfo({\n start: partStart,\n end: partEnd,\n appended: partIsAppended,\n segmentIndex,\n partIndex\n });\n currentPartStart = partEnd;\n newDiagnostics += `Media Sequence: ${currentMediaSequence}.${partIndex} | Range: ${partStart} --> ${partEnd} | Appended: ${partIsAppended}\\n`;\n part.syncInfo = partSyncInfo;\n return partSyncInfo;\n });\n newStorage.set(currentMediaSequence, new SyncInfoData(segmentSyncInfo, partsSyncInfo));\n newDiagnostics += `${compactSegmentUrlDescription(segment.resolvedUri)} | Media Sequence: ${currentMediaSequence} | Range: ${segmentStart} --> ${segmentEnd} | Appended: ${segmentIsAppended}\\n`;\n currentMediaSequence++;\n currentStart = segmentEnd;\n });\n this.end_ = currentStart;\n this.storage_ = newStorage;\n this.diagnostics_ = newDiagnostics;\n }\n\n calculateBaseTime_(mediaSequence, segments, fallback) {\n if (!this.storage_.size) {\n // Initial setup flow.\n return 0;\n }\n\n if (this.storage_.has(mediaSequence)) {\n // Normal flow.\n return this.storage_.get(mediaSequence).segmentSyncInfo.start;\n }\n\n const minMediaSequenceFromStorage = Math.min(...this.storage_.keys()); // This case captures a race condition that can occur if we switch to a new media playlist that is out of date\n // and still has an older Media Sequence. If this occurs, we extrapolate backwards to get the base time.\n\n if (mediaSequence < minMediaSequenceFromStorage) {\n const mediaSequenceDiff = minMediaSequenceFromStorage - mediaSequence;\n let baseTime = this.storage_.get(minMediaSequenceFromStorage).segmentSyncInfo.start;\n\n for (let i = 0; i < mediaSequenceDiff; i++) {\n const segment = segments[i];\n baseTime -= segment.duration;\n }\n\n return baseTime;\n } // Fallback flow.\n // There is a gap between last recorded playlist and a new one received.\n\n\n return fallback;\n }\n\n isReliablePlaylist_(mediaSequence, segments) {\n return mediaSequence !== undefined && mediaSequence !== null && Array.isArray(segments) && segments.length;\n }\n\n}\nclass DependantMediaSequenceSync extends MediaSequenceSync {\n constructor(parent) {\n super();\n this.parent_ = parent;\n }\n\n calculateBaseTime_(mediaSequence, segments, fallback) {\n if (!this.storage_.size) {\n const info = this.parent_.getSyncInfoForMediaSequence(mediaSequence);\n\n if (info) {\n return info.segmentSyncInfo.start;\n }\n\n return 0;\n }\n\n return super.calculateBaseTime_(mediaSequence, segments, fallback);\n }\n\n}\n\n/**\n * @file sync-controller.js\n */\n// synchronize expired playlist segments.\n// the max media sequence diff is 48 hours of live stream\n// content with two second segments. Anything larger than that\n// will likely be invalid.\n\nconst MAX_MEDIA_SEQUENCE_DIFF_FOR_SYNC = 86400;\nconst syncPointStrategies = [// Stategy \"VOD\": Handle the VOD-case where the sync-point is *always*\n// the equivalence display-time 0 === segment-index 0\n{\n name: 'VOD',\n run: (syncController, playlist, duration, currentTimeline, currentTime) => {\n if (duration !== Infinity) {\n const syncPoint = {\n time: 0,\n segmentIndex: 0,\n partIndex: null\n };\n return syncPoint;\n }\n\n return null;\n }\n}, {\n name: 'MediaSequence',\n\n /**\n * run media sequence strategy\n *\n * @param {SyncController} syncController\n * @param {Object} playlist\n * @param {number} duration\n * @param {number} currentTimeline\n * @param {number} currentTime\n * @param {string} type\n */\n run: (syncController, playlist, duration, currentTimeline, currentTime, type) => {\n const mediaSequenceSync = syncController.getMediaSequenceSync(type);\n\n if (!mediaSequenceSync) {\n return null;\n }\n\n if (!mediaSequenceSync.isReliable) {\n return null;\n }\n\n const syncInfo = mediaSequenceSync.getSyncInfoForTime(currentTime);\n\n if (!syncInfo) {\n return null;\n }\n\n return {\n time: syncInfo.start,\n partIndex: syncInfo.partIndex,\n segmentIndex: syncInfo.segmentIndex\n };\n }\n}, // Stategy \"ProgramDateTime\": We have a program-date-time tag in this playlist\n{\n name: 'ProgramDateTime',\n run: (syncController, playlist, duration, currentTimeline, currentTime) => {\n if (!Object.keys(syncController.timelineToDatetimeMappings).length) {\n return null;\n }\n\n let syncPoint = null;\n let lastDistance = null;\n const partsAndSegments = getPartsAndSegments(playlist);\n currentTime = currentTime || 0;\n\n for (let i = 0; i < partsAndSegments.length; i++) {\n // start from the end and loop backwards for live\n // or start from the front and loop forwards for non-live\n const index = playlist.endList || currentTime === 0 ? i : partsAndSegments.length - (i + 1);\n const partAndSegment = partsAndSegments[index];\n const segment = partAndSegment.segment;\n const datetimeMapping = syncController.timelineToDatetimeMappings[segment.timeline];\n\n if (!datetimeMapping || !segment.dateTimeObject) {\n continue;\n }\n\n const segmentTime = segment.dateTimeObject.getTime() / 1000;\n let start = segmentTime + datetimeMapping; // take part duration into account.\n\n if (segment.parts && typeof partAndSegment.partIndex === 'number') {\n for (let z = 0; z < partAndSegment.partIndex; z++) {\n start += segment.parts[z].duration;\n }\n }\n\n const distance = Math.abs(currentTime - start); // Once the distance begins to increase, or if distance is 0, we have passed\n // currentTime and can stop looking for better candidates\n\n if (lastDistance !== null && (distance === 0 || lastDistance < distance)) {\n break;\n }\n\n lastDistance = distance;\n syncPoint = {\n time: start,\n segmentIndex: partAndSegment.segmentIndex,\n partIndex: partAndSegment.partIndex\n };\n }\n\n return syncPoint;\n }\n}, // Stategy \"Segment\": We have a known time mapping for a timeline and a\n// segment in the current timeline with timing data\n{\n name: 'Segment',\n run: (syncController, playlist, duration, currentTimeline, currentTime) => {\n let syncPoint = null;\n let lastDistance = null;\n currentTime = currentTime || 0;\n const partsAndSegments = getPartsAndSegments(playlist);\n\n for (let i = 0; i < partsAndSegments.length; i++) {\n // start from the end and loop backwards for live\n // or start from the front and loop forwards for non-live\n const index = playlist.endList || currentTime === 0 ? i : partsAndSegments.length - (i + 1);\n const partAndSegment = partsAndSegments[index];\n const segment = partAndSegment.segment;\n const start = partAndSegment.part && partAndSegment.part.start || segment && segment.start;\n\n if (segment.timeline === currentTimeline && typeof start !== 'undefined') {\n const distance = Math.abs(currentTime - start); // Once the distance begins to increase, we have passed\n // currentTime and can stop looking for better candidates\n\n if (lastDistance !== null && lastDistance < distance) {\n break;\n }\n\n if (!syncPoint || lastDistance === null || lastDistance >= distance) {\n lastDistance = distance;\n syncPoint = {\n time: start,\n segmentIndex: partAndSegment.segmentIndex,\n partIndex: partAndSegment.partIndex\n };\n }\n }\n }\n\n return syncPoint;\n }\n}, // Stategy \"Discontinuity\": We have a discontinuity with a known\n// display-time\n{\n name: 'Discontinuity',\n run: (syncController, playlist, duration, currentTimeline, currentTime) => {\n let syncPoint = null;\n currentTime = currentTime || 0;\n\n if (playlist.discontinuityStarts && playlist.discontinuityStarts.length) {\n let lastDistance = null;\n\n for (let i = 0; i < playlist.discontinuityStarts.length; i++) {\n const segmentIndex = playlist.discontinuityStarts[i];\n const discontinuity = playlist.discontinuitySequence + i + 1;\n const discontinuitySync = syncController.discontinuities[discontinuity];\n\n if (discontinuitySync) {\n const distance = Math.abs(currentTime - discontinuitySync.time); // Once the distance begins to increase, we have passed\n // currentTime and can stop looking for better candidates\n\n if (lastDistance !== null && lastDistance < distance) {\n break;\n }\n\n if (!syncPoint || lastDistance === null || lastDistance >= distance) {\n lastDistance = distance;\n syncPoint = {\n time: discontinuitySync.time,\n segmentIndex,\n partIndex: null\n };\n }\n }\n }\n }\n\n return syncPoint;\n }\n}, // Stategy \"Playlist\": We have a playlist with a known mapping of\n// segment index to display time\n{\n name: 'Playlist',\n run: (syncController, playlist, duration, currentTimeline, currentTime) => {\n if (playlist.syncInfo) {\n const syncPoint = {\n time: playlist.syncInfo.time,\n segmentIndex: playlist.syncInfo.mediaSequence - playlist.mediaSequence,\n partIndex: null\n };\n return syncPoint;\n }\n\n return null;\n }\n}];\nclass SyncController extends videojs.EventTarget {\n constructor(options = {}) {\n super(); // ...for synching across variants\n\n this.timelines = [];\n this.discontinuities = [];\n this.timelineToDatetimeMappings = {}; // TODO: this map should be only available for HLS. Since only HLS has MediaSequence.\n // For some reason this map helps with syncing between quality switch for MPEG-DASH as well.\n // Moreover if we disable this map for MPEG-DASH - quality switch will be broken.\n // MPEG-DASH should have its own separate sync strategy\n\n const main = new MediaSequenceSync();\n const audio = new DependantMediaSequenceSync(main);\n const vtt = new DependantMediaSequenceSync(main);\n this.mediaSequenceStorage_ = {\n main,\n audio,\n vtt\n };\n this.logger_ = logger('SyncController');\n }\n /**\n *\n * @param {string} loaderType\n * @return {MediaSequenceSync|null}\n */\n\n\n getMediaSequenceSync(loaderType) {\n return this.mediaSequenceStorage_[loaderType] || null;\n }\n /**\n * Find a sync-point for the playlist specified\n *\n * A sync-point is defined as a known mapping from display-time to\n * a segment-index in the current playlist.\n *\n * @param {Playlist} playlist\n * The playlist that needs a sync-point\n * @param {number} duration\n * Duration of the MediaSource (Infinite if playing a live source)\n * @param {number} currentTimeline\n * The last timeline from which a segment was loaded\n * @param {number} currentTime\n * Current player's time\n * @param {string} type\n * Segment loader type\n * @return {Object}\n * A sync-point object\n */\n\n\n getSyncPoint(playlist, duration, currentTimeline, currentTime, type) {\n // Always use VOD sync point for VOD\n if (duration !== Infinity) {\n const vodSyncPointStrategy = syncPointStrategies.find(({\n name\n }) => name === 'VOD');\n return vodSyncPointStrategy.run(this, playlist, duration);\n }\n\n const syncPoints = this.runStrategies_(playlist, duration, currentTimeline, currentTime, type);\n\n if (!syncPoints.length) {\n // Signal that we need to attempt to get a sync-point manually\n // by fetching a segment in the playlist and constructing\n // a sync-point from that information\n return null;\n } // If we have exact match just return it instead of finding the nearest distance\n\n\n for (const syncPointInfo of syncPoints) {\n const {\n syncPoint,\n strategy\n } = syncPointInfo;\n const {\n segmentIndex,\n time\n } = syncPoint;\n\n if (segmentIndex < 0) {\n continue;\n }\n\n const selectedSegment = playlist.segments[segmentIndex];\n const start = time;\n const end = start + selectedSegment.duration;\n this.logger_(`Strategy: ${strategy}. Current time: ${currentTime}. selected segment: ${segmentIndex}. Time: [${start} -> ${end}]}`);\n\n if (currentTime >= start && currentTime < end) {\n this.logger_('Found sync point with exact match: ', syncPoint);\n return syncPoint;\n }\n } // Now find the sync-point that is closest to the currentTime because\n // that should result in the most accurate guess about which segment\n // to fetch\n\n\n return this.selectSyncPoint_(syncPoints, {\n key: 'time',\n value: currentTime\n });\n }\n /**\n * Calculate the amount of time that has expired off the playlist during playback\n *\n * @param {Playlist} playlist\n * Playlist object to calculate expired from\n * @param {number} duration\n * Duration of the MediaSource (Infinity if playling a live source)\n * @return {number|null}\n * The amount of time that has expired off the playlist during playback. Null\n * if no sync-points for the playlist can be found.\n */\n\n\n getExpiredTime(playlist, duration) {\n if (!playlist || !playlist.segments) {\n return null;\n }\n\n const syncPoints = this.runStrategies_(playlist, duration, playlist.discontinuitySequence, 0); // Without sync-points, there is not enough information to determine the expired time\n\n if (!syncPoints.length) {\n return null;\n }\n\n const syncPoint = this.selectSyncPoint_(syncPoints, {\n key: 'segmentIndex',\n value: 0\n }); // If the sync-point is beyond the start of the playlist, we want to subtract the\n // duration from index 0 to syncPoint.segmentIndex instead of adding.\n\n if (syncPoint.segmentIndex > 0) {\n syncPoint.time *= -1;\n }\n\n return Math.abs(syncPoint.time + sumDurations({\n defaultDuration: playlist.targetDuration,\n durationList: playlist.segments,\n startIndex: syncPoint.segmentIndex,\n endIndex: 0\n }));\n }\n /**\n * Runs each sync-point strategy and returns a list of sync-points returned by the\n * strategies\n *\n * @private\n * @param {Playlist} playlist\n * The playlist that needs a sync-point\n * @param {number} duration\n * Duration of the MediaSource (Infinity if playing a live source)\n * @param {number} currentTimeline\n * The last timeline from which a segment was loaded\n * @param {number} currentTime\n * Current player's time\n * @param {string} type\n * Segment loader type\n * @return {Array}\n * A list of sync-point objects\n */\n\n\n runStrategies_(playlist, duration, currentTimeline, currentTime, type) {\n const syncPoints = []; // Try to find a sync-point in by utilizing various strategies...\n\n for (let i = 0; i < syncPointStrategies.length; i++) {\n const strategy = syncPointStrategies[i];\n const syncPoint = strategy.run(this, playlist, duration, currentTimeline, currentTime, type);\n\n if (syncPoint) {\n syncPoint.strategy = strategy.name;\n syncPoints.push({\n strategy: strategy.name,\n syncPoint\n });\n }\n }\n\n return syncPoints;\n }\n /**\n * Selects the sync-point nearest the specified target\n *\n * @private\n * @param {Array} syncPoints\n * List of sync-points to select from\n * @param {Object} target\n * Object specifying the property and value we are targeting\n * @param {string} target.key\n * Specifies the property to target. Must be either 'time' or 'segmentIndex'\n * @param {number} target.value\n * The value to target for the specified key.\n * @return {Object}\n * The sync-point nearest the target\n */\n\n\n selectSyncPoint_(syncPoints, target) {\n let bestSyncPoint = syncPoints[0].syncPoint;\n let bestDistance = Math.abs(syncPoints[0].syncPoint[target.key] - target.value);\n let bestStrategy = syncPoints[0].strategy;\n\n for (let i = 1; i < syncPoints.length; i++) {\n const newDistance = Math.abs(syncPoints[i].syncPoint[target.key] - target.value);\n\n if (newDistance < bestDistance) {\n bestDistance = newDistance;\n bestSyncPoint = syncPoints[i].syncPoint;\n bestStrategy = syncPoints[i].strategy;\n }\n }\n\n this.logger_(`syncPoint for [${target.key}: ${target.value}] chosen with strategy` + ` [${bestStrategy}]: [time:${bestSyncPoint.time},` + ` segmentIndex:${bestSyncPoint.segmentIndex}` + (typeof bestSyncPoint.partIndex === 'number' ? `,partIndex:${bestSyncPoint.partIndex}` : '') + ']');\n return bestSyncPoint;\n }\n /**\n * Save any meta-data present on the segments when segments leave\n * the live window to the playlist to allow for synchronization at the\n * playlist level later.\n *\n * @param {Playlist} oldPlaylist - The previous active playlist\n * @param {Playlist} newPlaylist - The updated and most current playlist\n */\n\n\n saveExpiredSegmentInfo(oldPlaylist, newPlaylist) {\n const mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence; // Ignore large media sequence gaps\n\n if (mediaSequenceDiff > MAX_MEDIA_SEQUENCE_DIFF_FOR_SYNC) {\n videojs.log.warn(`Not saving expired segment info. Media sequence gap ${mediaSequenceDiff} is too large.`);\n return;\n } // When a segment expires from the playlist and it has a start time\n // save that information as a possible sync-point reference in future\n\n\n for (let i = mediaSequenceDiff - 1; i >= 0; i--) {\n const lastRemovedSegment = oldPlaylist.segments[i];\n\n if (lastRemovedSegment && typeof lastRemovedSegment.start !== 'undefined') {\n newPlaylist.syncInfo = {\n mediaSequence: oldPlaylist.mediaSequence + i,\n time: lastRemovedSegment.start\n };\n this.logger_(`playlist refresh sync: [time:${newPlaylist.syncInfo.time},` + ` mediaSequence: ${newPlaylist.syncInfo.mediaSequence}]`);\n this.trigger('syncinfoupdate');\n break;\n }\n }\n }\n /**\n * Save the mapping from playlist's ProgramDateTime to display. This should only happen\n * before segments start to load.\n *\n * @param {Playlist} playlist - The currently active playlist\n */\n\n\n setDateTimeMappingForStart(playlist) {\n // It's possible for the playlist to be updated before playback starts, meaning time\n // zero is not yet set. If, during these playlist refreshes, a discontinuity is\n // crossed, then the old time zero mapping (for the prior timeline) would be retained\n // unless the mappings are cleared.\n this.timelineToDatetimeMappings = {};\n\n if (playlist.segments && playlist.segments.length && playlist.segments[0].dateTimeObject) {\n const firstSegment = playlist.segments[0];\n const playlistTimestamp = firstSegment.dateTimeObject.getTime() / 1000;\n this.timelineToDatetimeMappings[firstSegment.timeline] = -playlistTimestamp;\n }\n }\n /**\n * Calculates and saves timeline mappings, playlist sync info, and segment timing values\n * based on the latest timing information.\n *\n * @param {Object} options\n * Options object\n * @param {SegmentInfo} options.segmentInfo\n * The current active request information\n * @param {boolean} options.shouldSaveTimelineMapping\n * If there's a timeline change, determines if the timeline mapping should be\n * saved for timeline mapping and program date time mappings.\n */\n\n\n saveSegmentTimingInfo({\n segmentInfo,\n shouldSaveTimelineMapping\n }) {\n const didCalculateSegmentTimeMapping = this.calculateSegmentTimeMapping_(segmentInfo, segmentInfo.timingInfo, shouldSaveTimelineMapping);\n const segment = segmentInfo.segment;\n\n if (didCalculateSegmentTimeMapping) {\n this.saveDiscontinuitySyncInfo_(segmentInfo); // If the playlist does not have sync information yet, record that information\n // now with segment timing information\n\n if (!segmentInfo.playlist.syncInfo) {\n segmentInfo.playlist.syncInfo = {\n mediaSequence: segmentInfo.playlist.mediaSequence + segmentInfo.mediaIndex,\n time: segment.start\n };\n }\n }\n\n const dateTime = segment.dateTimeObject;\n\n if (segment.discontinuity && shouldSaveTimelineMapping && dateTime) {\n this.timelineToDatetimeMappings[segment.timeline] = -(dateTime.getTime() / 1000);\n }\n }\n\n timestampOffsetForTimeline(timeline) {\n if (typeof this.timelines[timeline] === 'undefined') {\n return null;\n }\n\n return this.timelines[timeline].time;\n }\n\n mappingForTimeline(timeline) {\n if (typeof this.timelines[timeline] === 'undefined') {\n return null;\n }\n\n return this.timelines[timeline].mapping;\n }\n /**\n * Use the \"media time\" for a segment to generate a mapping to \"display time\" and\n * save that display time to the segment.\n *\n * @private\n * @param {SegmentInfo} segmentInfo\n * The current active request information\n * @param {Object} timingInfo\n * The start and end time of the current segment in \"media time\"\n * @param {boolean} shouldSaveTimelineMapping\n * If there's a timeline change, determines if the timeline mapping should be\n * saved in timelines.\n * @return {boolean}\n * Returns false if segment time mapping could not be calculated\n */\n\n\n calculateSegmentTimeMapping_(segmentInfo, timingInfo, shouldSaveTimelineMapping) {\n // TODO: remove side effects\n const segment = segmentInfo.segment;\n const part = segmentInfo.part;\n let mappingObj = this.timelines[segmentInfo.timeline];\n let start;\n let end;\n\n if (typeof segmentInfo.timestampOffset === 'number') {\n mappingObj = {\n time: segmentInfo.startOfSegment,\n mapping: segmentInfo.startOfSegment - timingInfo.start\n };\n\n if (shouldSaveTimelineMapping) {\n this.timelines[segmentInfo.timeline] = mappingObj;\n this.trigger('timestampoffset');\n this.logger_(`time mapping for timeline ${segmentInfo.timeline}: ` + `[time: ${mappingObj.time}] [mapping: ${mappingObj.mapping}]`);\n }\n\n start = segmentInfo.startOfSegment;\n end = timingInfo.end + mappingObj.mapping;\n } else if (mappingObj) {\n start = timingInfo.start + mappingObj.mapping;\n end = timingInfo.end + mappingObj.mapping;\n } else {\n return false;\n }\n\n if (part) {\n part.start = start;\n part.end = end;\n } // If we don't have a segment start yet or the start value we got\n // is less than our current segment.start value, save a new start value.\n // We have to do this because parts will have segment timing info saved\n // multiple times and we want segment start to be the earliest part start\n // value for that segment.\n\n\n if (!segment.start || start < segment.start) {\n segment.start = start;\n }\n\n segment.end = end;\n return true;\n }\n /**\n * Each time we have discontinuity in the playlist, attempt to calculate the location\n * in display of the start of the discontinuity and save that. We also save an accuracy\n * value so that we save values with the most accuracy (closest to 0.)\n *\n * @private\n * @param {SegmentInfo} segmentInfo - The current active request information\n */\n\n\n saveDiscontinuitySyncInfo_(segmentInfo) {\n const playlist = segmentInfo.playlist;\n const segment = segmentInfo.segment; // If the current segment is a discontinuity then we know exactly where\n // the start of the range and it's accuracy is 0 (greater accuracy values\n // mean more approximation)\n\n if (segment.discontinuity) {\n this.discontinuities[segment.timeline] = {\n time: segment.start,\n accuracy: 0\n };\n } else if (playlist.discontinuityStarts && playlist.discontinuityStarts.length) {\n // Search for future discontinuities that we can provide better timing\n // information for and save that information for sync purposes\n for (let i = 0; i < playlist.discontinuityStarts.length; i++) {\n const segmentIndex = playlist.discontinuityStarts[i];\n const discontinuity = playlist.discontinuitySequence + i + 1;\n const mediaIndexDiff = segmentIndex - segmentInfo.mediaIndex;\n const accuracy = Math.abs(mediaIndexDiff);\n\n if (!this.discontinuities[discontinuity] || this.discontinuities[discontinuity].accuracy > accuracy) {\n let time;\n\n if (mediaIndexDiff < 0) {\n time = segment.start - sumDurations({\n defaultDuration: playlist.targetDuration,\n durationList: playlist.segments,\n startIndex: segmentInfo.mediaIndex,\n endIndex: segmentIndex\n });\n } else {\n time = segment.end + sumDurations({\n defaultDuration: playlist.targetDuration,\n durationList: playlist.segments,\n startIndex: segmentInfo.mediaIndex + 1,\n endIndex: segmentIndex\n });\n }\n\n this.discontinuities[discontinuity] = {\n time,\n accuracy\n };\n }\n }\n }\n }\n\n dispose() {\n this.trigger('dispose');\n this.off();\n }\n\n}\n\n/**\n * The TimelineChangeController acts as a source for segment loaders to listen for and\n * keep track of latest and pending timeline changes. This is useful to ensure proper\n * sync, as each loader may need to make a consideration for what timeline the other\n * loader is on before making changes which could impact the other loader's media.\n *\n * @class TimelineChangeController\n * @extends videojs.EventTarget\n */\n\nclass TimelineChangeController extends videojs.EventTarget {\n constructor() {\n super();\n this.pendingTimelineChanges_ = {};\n this.lastTimelineChanges_ = {};\n }\n\n clearPendingTimelineChange(type) {\n this.pendingTimelineChanges_[type] = null;\n this.trigger('pendingtimelinechange');\n }\n\n pendingTimelineChange({\n type,\n from,\n to\n }) {\n if (typeof from === 'number' && typeof to === 'number') {\n this.pendingTimelineChanges_[type] = {\n type,\n from,\n to\n };\n this.trigger('pendingtimelinechange');\n }\n\n return this.pendingTimelineChanges_[type];\n }\n\n lastTimelineChange({\n type,\n from,\n to\n }) {\n if (typeof from === 'number' && typeof to === 'number') {\n this.lastTimelineChanges_[type] = {\n type,\n from,\n to\n };\n delete this.pendingTimelineChanges_[type];\n const metadata = {\n timelineChangeInfo: {\n from,\n to\n }\n };\n this.trigger({\n type: 'timelinechange',\n metadata\n });\n }\n\n return this.lastTimelineChanges_[type];\n }\n\n dispose() {\n this.trigger('dispose');\n this.pendingTimelineChanges_ = {};\n this.lastTimelineChanges_ = {};\n this.off();\n }\n\n}\n\n/* rollup-plugin-worker-factory start for worker!/home/runner/work/http-streaming/http-streaming/src/decrypter-worker.js */\nconst workerCode = transform(getWorkerString(function () {\n /**\n * @file stream.js\n */\n\n /**\n * A lightweight readable stream implemention that handles event dispatching.\n *\n * @class Stream\n */\n\n var Stream = /*#__PURE__*/function () {\n function Stream() {\n this.listeners = {};\n }\n /**\n * Add a listener for a specified event type.\n *\n * @param {string} type the event name\n * @param {Function} listener the callback to be invoked when an event of\n * the specified type occurs\n */\n\n\n var _proto = Stream.prototype;\n\n _proto.on = function on(type, listener) {\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n\n this.listeners[type].push(listener);\n }\n /**\n * Remove a listener for a specified event type.\n *\n * @param {string} type the event name\n * @param {Function} listener a function previously registered for this\n * type of event through `on`\n * @return {boolean} if we could turn it off or not\n */\n ;\n\n _proto.off = function off(type, listener) {\n if (!this.listeners[type]) {\n return false;\n }\n\n var index = this.listeners[type].indexOf(listener); // TODO: which is better?\n // In Video.js we slice listener functions\n // on trigger so that it does not mess up the order\n // while we loop through.\n //\n // Here we slice on off so that the loop in trigger\n // can continue using it's old reference to loop without\n // messing up the order.\n\n this.listeners[type] = this.listeners[type].slice(0);\n this.listeners[type].splice(index, 1);\n return index > -1;\n }\n /**\n * Trigger an event of the specified type on this stream. Any additional\n * arguments to this function are passed as parameters to event listeners.\n *\n * @param {string} type the event name\n */\n ;\n\n _proto.trigger = function trigger(type) {\n var callbacks = this.listeners[type];\n\n if (!callbacks) {\n return;\n } // Slicing the arguments on every invocation of this method\n // can add a significant amount of overhead. Avoid the\n // intermediate object creation for the common case of a\n // single callback argument\n\n\n if (arguments.length === 2) {\n var length = callbacks.length;\n\n for (var i = 0; i < length; ++i) {\n callbacks[i].call(this, arguments[1]);\n }\n } else {\n var args = Array.prototype.slice.call(arguments, 1);\n var _length = callbacks.length;\n\n for (var _i = 0; _i < _length; ++_i) {\n callbacks[_i].apply(this, args);\n }\n }\n }\n /**\n * Destroys the stream and cleans up.\n */\n ;\n\n _proto.dispose = function dispose() {\n this.listeners = {};\n }\n /**\n * Forwards all `data` events on this stream to the destination stream. The\n * destination stream should provide a method `push` to receive the data\n * events as they arrive.\n *\n * @param {Stream} destination the stream that will receive all `data` events\n * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options\n */\n ;\n\n _proto.pipe = function pipe(destination) {\n this.on('data', function (data) {\n destination.push(data);\n });\n };\n\n return Stream;\n }();\n /*! @name pkcs7 @version 1.0.4 @license Apache-2.0 */\n\n /**\n * Returns the subarray of a Uint8Array without PKCS#7 padding.\n *\n * @param padded {Uint8Array} unencrypted bytes that have been padded\n * @return {Uint8Array} the unpadded bytes\n * @see http://tools.ietf.org/html/rfc5652\n */\n\n\n function unpad(padded) {\n return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]);\n }\n /*! @name aes-decrypter @version 4.0.2 @license Apache-2.0 */\n\n /**\n * @file aes.js\n *\n * This file contains an adaptation of the AES decryption algorithm\n * from the Standford Javascript Cryptography Library. That work is\n * covered by the following copyright and permissions notice:\n *\n * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above\n * copyright notice, this list of conditions and the following\n * disclaimer in the documentation and/or other materials provided\n * with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * The views and conclusions contained in the software and documentation\n * are those of the authors and should not be interpreted as representing\n * official policies, either expressed or implied, of the authors.\n */\n\n /**\n * Expand the S-box tables.\n *\n * @private\n */\n\n\n const precompute = function () {\n const tables = [[[], [], [], [], []], [[], [], [], [], []]];\n const encTable = tables[0];\n const decTable = tables[1];\n const sbox = encTable[4];\n const sboxInv = decTable[4];\n let i;\n let x;\n let xInv;\n const d = [];\n const th = [];\n let x2;\n let x4;\n let x8;\n let s;\n let tEnc;\n let tDec; // Compute double and third tables\n\n for (i = 0; i < 256; i++) {\n th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;\n }\n\n for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {\n // Compute sbox\n s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;\n s = s >> 8 ^ s & 255 ^ 99;\n sbox[x] = s;\n sboxInv[s] = x; // Compute MixColumns\n\n x8 = d[x4 = d[x2 = d[x]]];\n tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;\n tEnc = d[s] * 0x101 ^ s * 0x1010100;\n\n for (i = 0; i < 4; i++) {\n encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;\n decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;\n }\n } // Compactify. Considerable speedup on Firefox.\n\n\n for (i = 0; i < 5; i++) {\n encTable[i] = encTable[i].slice(0);\n decTable[i] = decTable[i].slice(0);\n }\n\n return tables;\n };\n\n let aesTables = null;\n /**\n * Schedule out an AES key for both encryption and decryption. This\n * is a low-level class. Use a cipher mode to do bulk encryption.\n *\n * @class AES\n * @param key {Array} The key as an array of 4, 6 or 8 words.\n */\n\n class AES {\n constructor(key) {\n /**\n * The expanded S-box and inverse S-box tables. These will be computed\n * on the client so that we don't have to send them down the wire.\n *\n * There are two tables, _tables[0] is for encryption and\n * _tables[1] is for decryption.\n *\n * The first 4 sub-tables are the expanded S-box with MixColumns. The\n * last (_tables[01][4]) is the S-box itself.\n *\n * @private\n */\n // if we have yet to precompute the S-box tables\n // do so now\n if (!aesTables) {\n aesTables = precompute();\n } // then make a copy of that object for use\n\n\n this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]];\n let i;\n let j;\n let tmp;\n const sbox = this._tables[0][4];\n const decTable = this._tables[1];\n const keyLen = key.length;\n let rcon = 1;\n\n if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {\n throw new Error('Invalid aes key size');\n }\n\n const encKey = key.slice(0);\n const decKey = [];\n this._key = [encKey, decKey]; // schedule encryption keys\n\n for (i = keyLen; i < 4 * keyLen + 28; i++) {\n tmp = encKey[i - 1]; // apply sbox\n\n if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {\n tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; // shift rows and add rcon\n\n if (i % keyLen === 0) {\n tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;\n rcon = rcon << 1 ^ (rcon >> 7) * 283;\n }\n }\n\n encKey[i] = encKey[i - keyLen] ^ tmp;\n } // schedule decryption keys\n\n\n for (j = 0; i; j++, i--) {\n tmp = encKey[j & 3 ? i : i - 4];\n\n if (i <= 4 || j < 4) {\n decKey[j] = tmp;\n } else {\n decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]];\n }\n }\n }\n /**\n * Decrypt 16 bytes, specified as four 32-bit words.\n *\n * @param {number} encrypted0 the first word to decrypt\n * @param {number} encrypted1 the second word to decrypt\n * @param {number} encrypted2 the third word to decrypt\n * @param {number} encrypted3 the fourth word to decrypt\n * @param {Int32Array} out the array to write the decrypted words\n * into\n * @param {number} offset the offset into the output array to start\n * writing results\n * @return {Array} The plaintext.\n */\n\n\n decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {\n const key = this._key[1]; // state variables a,b,c,d are loaded with pre-whitened data\n\n let a = encrypted0 ^ key[0];\n let b = encrypted3 ^ key[1];\n let c = encrypted2 ^ key[2];\n let d = encrypted1 ^ key[3];\n let a2;\n let b2;\n let c2; // key.length === 2 ?\n\n const nInnerRounds = key.length / 4 - 2;\n let i;\n let kIndex = 4;\n const table = this._tables[1]; // load up the tables\n\n const table0 = table[0];\n const table1 = table[1];\n const table2 = table[2];\n const table3 = table[3];\n const sbox = table[4]; // Inner rounds. Cribbed from OpenSSL.\n\n for (i = 0; i < nInnerRounds; i++) {\n a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex];\n b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];\n c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];\n d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];\n kIndex += 4;\n a = a2;\n b = b2;\n c = c2;\n } // Last round.\n\n\n for (i = 0; i < 4; i++) {\n out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];\n a2 = a;\n a = b;\n b = c;\n c = d;\n d = a2;\n }\n }\n\n }\n /**\n * @file async-stream.js\n */\n\n /**\n * A wrapper around the Stream class to use setTimeout\n * and run stream \"jobs\" Asynchronously\n *\n * @class AsyncStream\n * @extends Stream\n */\n\n\n class AsyncStream extends Stream {\n constructor() {\n super(Stream);\n this.jobs = [];\n this.delay = 1;\n this.timeout_ = null;\n }\n /**\n * process an async job\n *\n * @private\n */\n\n\n processJob_() {\n this.jobs.shift()();\n\n if (this.jobs.length) {\n this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);\n } else {\n this.timeout_ = null;\n }\n }\n /**\n * push a job into the stream\n *\n * @param {Function} job the job to push into the stream\n */\n\n\n push(job) {\n this.jobs.push(job);\n\n if (!this.timeout_) {\n this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);\n }\n }\n\n }\n /**\n * @file decrypter.js\n *\n * An asynchronous implementation of AES-128 CBC decryption with\n * PKCS#7 padding.\n */\n\n /**\n * Convert network-order (big-endian) bytes into their little-endian\n * representation.\n */\n\n\n const ntoh = function (word) {\n return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;\n };\n /**\n * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.\n *\n * @param {Uint8Array} encrypted the encrypted bytes\n * @param {Uint32Array} key the bytes of the decryption key\n * @param {Uint32Array} initVector the initialization vector (IV) to\n * use for the first round of CBC.\n * @return {Uint8Array} the decrypted bytes\n *\n * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29\n * @see https://tools.ietf.org/html/rfc2315\n */\n\n\n const decrypt = function (encrypted, key, initVector) {\n // word-level access to the encrypted bytes\n const encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2);\n const decipher = new AES(Array.prototype.slice.call(key)); // byte and word-level access for the decrypted output\n\n const decrypted = new Uint8Array(encrypted.byteLength);\n const decrypted32 = new Int32Array(decrypted.buffer); // temporary variables for working with the IV, encrypted, and\n // decrypted data\n\n let init0;\n let init1;\n let init2;\n let init3;\n let encrypted0;\n let encrypted1;\n let encrypted2;\n let encrypted3; // iteration variable\n\n let wordIx; // pull out the words of the IV to ensure we don't modify the\n // passed-in reference and easier access\n\n init0 = initVector[0];\n init1 = initVector[1];\n init2 = initVector[2];\n init3 = initVector[3]; // decrypt four word sequences, applying cipher-block chaining (CBC)\n // to each decrypted block\n\n for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {\n // convert big-endian (network order) words into little-endian\n // (javascript order)\n encrypted0 = ntoh(encrypted32[wordIx]);\n encrypted1 = ntoh(encrypted32[wordIx + 1]);\n encrypted2 = ntoh(encrypted32[wordIx + 2]);\n encrypted3 = ntoh(encrypted32[wordIx + 3]); // decrypt the block\n\n decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx); // XOR with the IV, and restore network byte-order to obtain the\n // plaintext\n\n decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);\n decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);\n decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);\n decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3); // setup the IV for the next round\n\n init0 = encrypted0;\n init1 = encrypted1;\n init2 = encrypted2;\n init3 = encrypted3;\n }\n\n return decrypted;\n };\n /**\n * The `Decrypter` class that manages decryption of AES\n * data through `AsyncStream` objects and the `decrypt`\n * function\n *\n * @param {Uint8Array} encrypted the encrypted bytes\n * @param {Uint32Array} key the bytes of the decryption key\n * @param {Uint32Array} initVector the initialization vector (IV) to\n * @param {Function} done the function to run when done\n * @class Decrypter\n */\n\n\n class Decrypter {\n constructor(encrypted, key, initVector, done) {\n const step = Decrypter.STEP;\n const encrypted32 = new Int32Array(encrypted.buffer);\n const decrypted = new Uint8Array(encrypted.byteLength);\n let i = 0;\n this.asyncStream_ = new AsyncStream(); // split up the encryption job and do the individual chunks asynchronously\n\n this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));\n\n for (i = step; i < encrypted32.length; i += step) {\n initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]);\n this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));\n } // invoke the done() callback when everything is finished\n\n\n this.asyncStream_.push(function () {\n // remove pkcs#7 padding from the decrypted bytes\n done(null, unpad(decrypted));\n });\n }\n /**\n * a getter for step the maximum number of bytes to process at one time\n *\n * @return {number} the value of step 32000\n */\n\n\n static get STEP() {\n // 4 * 8000;\n return 32000;\n }\n /**\n * @private\n */\n\n\n decryptChunk_(encrypted, key, initVector, decrypted) {\n return function () {\n const bytes = decrypt(encrypted, key, initVector);\n decrypted.set(bytes, encrypted.byteOffset);\n };\n }\n\n }\n\n var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n var win;\n\n if (typeof window !== \"undefined\") {\n win = window;\n } else if (typeof commonjsGlobal !== \"undefined\") {\n win = commonjsGlobal;\n } else if (typeof self !== \"undefined\") {\n win = self;\n } else {\n win = {};\n }\n\n var window_1 = win;\n\n var isArrayBufferView = function isArrayBufferView(obj) {\n if (ArrayBuffer.isView === 'function') {\n return ArrayBuffer.isView(obj);\n }\n\n return obj && obj.buffer instanceof ArrayBuffer;\n };\n\n var BigInt = window_1.BigInt || Number;\n [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')];\n\n (function () {\n var a = new Uint16Array([0xFFCC]);\n var b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);\n\n if (b[0] === 0xFF) {\n return 'big';\n }\n\n if (b[0] === 0xCC) {\n return 'little';\n }\n\n return 'unknown';\n })();\n /**\n * Creates an object for sending to a web worker modifying properties that are TypedArrays\n * into a new object with seperated properties for the buffer, byteOffset, and byteLength.\n *\n * @param {Object} message\n * Object of properties and values to send to the web worker\n * @return {Object}\n * Modified message with TypedArray values expanded\n * @function createTransferableMessage\n */\n\n\n const createTransferableMessage = function (message) {\n const transferable = {};\n Object.keys(message).forEach(key => {\n const value = message[key];\n\n if (isArrayBufferView(value)) {\n transferable[key] = {\n bytes: value.buffer,\n byteOffset: value.byteOffset,\n byteLength: value.byteLength\n };\n } else {\n transferable[key] = value;\n }\n });\n return transferable;\n };\n /* global self */\n\n /**\n * Our web worker interface so that things can talk to aes-decrypter\n * that will be running in a web worker. the scope is passed to this by\n * webworkify.\n */\n\n\n self.onmessage = function (event) {\n const data = event.data;\n const encrypted = new Uint8Array(data.encrypted.bytes, data.encrypted.byteOffset, data.encrypted.byteLength);\n const key = new Uint32Array(data.key.bytes, data.key.byteOffset, data.key.byteLength / 4);\n const iv = new Uint32Array(data.iv.bytes, data.iv.byteOffset, data.iv.byteLength / 4);\n /* eslint-disable no-new, handle-callback-err */\n\n new Decrypter(encrypted, key, iv, function (err, bytes) {\n self.postMessage(createTransferableMessage({\n source: data.source,\n decrypted: bytes\n }), [bytes.buffer]);\n });\n /* eslint-enable */\n };\n}));\nvar Decrypter = factory(workerCode);\n/* rollup-plugin-worker-factory end for worker!/home/runner/work/http-streaming/http-streaming/src/decrypter-worker.js */\n\n/**\n * Convert the properties of an HLS track into an audioTrackKind.\n *\n * @private\n */\n\nconst audioTrackKind_ = properties => {\n let kind = properties.default ? 'main' : 'alternative';\n\n if (properties.characteristics && properties.characteristics.indexOf('public.accessibility.describes-video') >= 0) {\n kind = 'main-desc';\n }\n\n return kind;\n};\n/**\n * Pause provided segment loader and playlist loader if active\n *\n * @param {SegmentLoader} segmentLoader\n * SegmentLoader to pause\n * @param {Object} mediaType\n * Active media type\n * @function stopLoaders\n */\n\n\nconst stopLoaders = (segmentLoader, mediaType) => {\n segmentLoader.abort();\n segmentLoader.pause();\n\n if (mediaType && mediaType.activePlaylistLoader) {\n mediaType.activePlaylistLoader.pause();\n mediaType.activePlaylistLoader = null;\n }\n};\n/**\n * Start loading provided segment loader and playlist loader\n *\n * @param {PlaylistLoader} playlistLoader\n * PlaylistLoader to start loading\n * @param {Object} mediaType\n * Active media type\n * @function startLoaders\n */\n\nconst startLoaders = (playlistLoader, mediaType) => {\n // Segment loader will be started after `loadedmetadata` or `loadedplaylist` from the\n // playlist loader\n mediaType.activePlaylistLoader = playlistLoader;\n playlistLoader.load();\n};\n/**\n * Returns a function to be called when the media group changes. It performs a\n * non-destructive (preserve the buffer) resync of the SegmentLoader. This is because a\n * change of group is merely a rendition switch of the same content at another encoding,\n * rather than a change of content, such as switching audio from English to Spanish.\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Handler for a non-destructive resync of SegmentLoader when the active media\n * group changes.\n * @function onGroupChanged\n */\n\nconst onGroupChanged = (type, settings) => () => {\n const {\n segmentLoaders: {\n [type]: segmentLoader,\n main: mainSegmentLoader\n },\n mediaTypes: {\n [type]: mediaType\n }\n } = settings;\n const activeTrack = mediaType.activeTrack();\n const activeGroup = mediaType.getActiveGroup();\n const previousActiveLoader = mediaType.activePlaylistLoader;\n const lastGroup = mediaType.lastGroup_; // the group did not change do nothing\n\n if (activeGroup && lastGroup && activeGroup.id === lastGroup.id) {\n return;\n }\n\n mediaType.lastGroup_ = activeGroup;\n mediaType.lastTrack_ = activeTrack;\n stopLoaders(segmentLoader, mediaType);\n\n if (!activeGroup || activeGroup.isMainPlaylist) {\n // there is no group active or active group is a main playlist and won't change\n return;\n }\n\n if (!activeGroup.playlistLoader) {\n if (previousActiveLoader) {\n // The previous group had a playlist loader but the new active group does not\n // this means we are switching from demuxed to muxed audio. In this case we want to\n // do a destructive reset of the main segment loader and not restart the audio\n // loaders.\n mainSegmentLoader.resetEverything();\n }\n\n return;\n } // Non-destructive resync\n\n\n segmentLoader.resyncLoader();\n startLoaders(activeGroup.playlistLoader, mediaType);\n};\nconst onGroupChanging = (type, settings) => () => {\n const {\n segmentLoaders: {\n [type]: segmentLoader\n },\n mediaTypes: {\n [type]: mediaType\n }\n } = settings;\n mediaType.lastGroup_ = null;\n segmentLoader.abort();\n segmentLoader.pause();\n};\n/**\n * Returns a function to be called when the media track changes. It performs a\n * destructive reset of the SegmentLoader to ensure we start loading as close to\n * currentTime as possible.\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Handler for a destructive reset of SegmentLoader when the active media\n * track changes.\n * @function onTrackChanged\n */\n\nconst onTrackChanged = (type, settings) => () => {\n const {\n mainPlaylistLoader,\n segmentLoaders: {\n [type]: segmentLoader,\n main: mainSegmentLoader\n },\n mediaTypes: {\n [type]: mediaType\n }\n } = settings;\n const activeTrack = mediaType.activeTrack();\n const activeGroup = mediaType.getActiveGroup();\n const previousActiveLoader = mediaType.activePlaylistLoader;\n const lastTrack = mediaType.lastTrack_; // track did not change, do nothing\n\n if (lastTrack && activeTrack && lastTrack.id === activeTrack.id) {\n return;\n }\n\n mediaType.lastGroup_ = activeGroup;\n mediaType.lastTrack_ = activeTrack;\n stopLoaders(segmentLoader, mediaType);\n\n if (!activeGroup) {\n // there is no group active so we do not want to restart loaders\n return;\n }\n\n if (activeGroup.isMainPlaylist) {\n // track did not change, do nothing\n if (!activeTrack || !lastTrack || activeTrack.id === lastTrack.id) {\n return;\n }\n\n const pc = settings.vhs.playlistController_;\n const newPlaylist = pc.selectPlaylist(); // media will not change do nothing\n\n if (pc.media() === newPlaylist) {\n return;\n }\n\n mediaType.logger_(`track change. Switching main audio from ${lastTrack.id} to ${activeTrack.id}`);\n mainPlaylistLoader.pause();\n mainSegmentLoader.resetEverything();\n pc.fastQualityChange_(newPlaylist);\n return;\n }\n\n if (type === 'AUDIO') {\n if (!activeGroup.playlistLoader) {\n // when switching from demuxed audio/video to muxed audio/video (noted by no\n // playlist loader for the audio group), we want to do a destructive reset of the\n // main segment loader and not restart the audio loaders\n mainSegmentLoader.setAudio(true); // don't have to worry about disabling the audio of the audio segment loader since\n // it should be stopped\n\n mainSegmentLoader.resetEverything();\n return;\n } // although the segment loader is an audio segment loader, call the setAudio\n // function to ensure it is prepared to re-append the init segment (or handle other\n // config changes)\n\n\n segmentLoader.setAudio(true);\n mainSegmentLoader.setAudio(false);\n }\n\n if (previousActiveLoader === activeGroup.playlistLoader) {\n // Nothing has actually changed. This can happen because track change events can fire\n // multiple times for a \"single\" change. One for enabling the new active track, and\n // one for disabling the track that was active\n startLoaders(activeGroup.playlistLoader, mediaType);\n return;\n }\n\n if (segmentLoader.track) {\n // For WebVTT, set the new text track in the segmentloader\n segmentLoader.track(activeTrack);\n } // destructive reset\n\n\n segmentLoader.resetEverything();\n startLoaders(activeGroup.playlistLoader, mediaType);\n};\nconst onError = {\n /**\n * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters\n * an error.\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Error handler. Logs warning (or error if the playlist is excluded) to\n * console and switches back to default audio track.\n * @function onError.AUDIO\n */\n AUDIO: (type, settings) => () => {\n const {\n mediaTypes: {\n [type]: mediaType\n },\n excludePlaylist\n } = settings; // switch back to default audio track\n\n const activeTrack = mediaType.activeTrack();\n const activeGroup = mediaType.activeGroup();\n const id = (activeGroup.filter(group => group.default)[0] || activeGroup[0]).id;\n const defaultTrack = mediaType.tracks[id];\n\n if (activeTrack === defaultTrack) {\n // Default track encountered an error. All we can do now is exclude the current\n // rendition and hope another will switch audio groups\n excludePlaylist({\n error: {\n message: 'Problem encountered loading the default audio track.'\n }\n });\n return;\n }\n\n videojs.log.warn('Problem encountered loading the alternate audio track.' + 'Switching back to default.');\n\n for (const trackId in mediaType.tracks) {\n mediaType.tracks[trackId].enabled = mediaType.tracks[trackId] === defaultTrack;\n }\n\n mediaType.onTrackChanged();\n },\n\n /**\n * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters\n * an error.\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Error handler. Logs warning to console and disables the active subtitle track\n * @function onError.SUBTITLES\n */\n SUBTITLES: (type, settings) => () => {\n const {\n mediaTypes: {\n [type]: mediaType\n }\n } = settings;\n videojs.log.warn('Problem encountered loading the subtitle track.' + 'Disabling subtitle track.');\n const track = mediaType.activeTrack();\n\n if (track) {\n track.mode = 'disabled';\n }\n\n mediaType.onTrackChanged();\n }\n};\nconst setupListeners = {\n /**\n * Setup event listeners for audio playlist loader\n *\n * @param {string} type\n * MediaGroup type\n * @param {PlaylistLoader|null} playlistLoader\n * PlaylistLoader to register listeners on\n * @param {Object} settings\n * Object containing required information for media groups\n * @function setupListeners.AUDIO\n */\n AUDIO: (type, playlistLoader, settings) => {\n if (!playlistLoader) {\n // no playlist loader means audio will be muxed with the video\n return;\n }\n\n const {\n tech,\n requestOptions,\n segmentLoaders: {\n [type]: segmentLoader\n }\n } = settings;\n playlistLoader.on('loadedmetadata', () => {\n const media = playlistLoader.media();\n segmentLoader.playlist(media, requestOptions); // if the video is already playing, or if this isn't a live video and preload\n // permits, start downloading segments\n\n if (!tech.paused() || media.endList && tech.preload() !== 'none') {\n segmentLoader.load();\n }\n });\n playlistLoader.on('loadedplaylist', () => {\n segmentLoader.playlist(playlistLoader.media(), requestOptions); // If the player isn't paused, ensure that the segment loader is running\n\n if (!tech.paused()) {\n segmentLoader.load();\n }\n });\n playlistLoader.on('error', onError[type](type, settings));\n },\n\n /**\n * Setup event listeners for subtitle playlist loader\n *\n * @param {string} type\n * MediaGroup type\n * @param {PlaylistLoader|null} playlistLoader\n * PlaylistLoader to register listeners on\n * @param {Object} settings\n * Object containing required information for media groups\n * @function setupListeners.SUBTITLES\n */\n SUBTITLES: (type, playlistLoader, settings) => {\n const {\n tech,\n requestOptions,\n segmentLoaders: {\n [type]: segmentLoader\n },\n mediaTypes: {\n [type]: mediaType\n }\n } = settings;\n playlistLoader.on('loadedmetadata', () => {\n const media = playlistLoader.media();\n segmentLoader.playlist(media, requestOptions);\n segmentLoader.track(mediaType.activeTrack()); // if the video is already playing, or if this isn't a live video and preload\n // permits, start downloading segments\n\n if (!tech.paused() || media.endList && tech.preload() !== 'none') {\n segmentLoader.load();\n }\n });\n playlistLoader.on('loadedplaylist', () => {\n segmentLoader.playlist(playlistLoader.media(), requestOptions); // If the player isn't paused, ensure that the segment loader is running\n\n if (!tech.paused()) {\n segmentLoader.load();\n }\n });\n playlistLoader.on('error', onError[type](type, settings));\n }\n};\nconst initialize = {\n /**\n * Setup PlaylistLoaders and AudioTracks for the audio groups\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @function initialize.AUDIO\n */\n 'AUDIO': (type, settings) => {\n const {\n vhs,\n sourceType,\n segmentLoaders: {\n [type]: segmentLoader\n },\n requestOptions,\n main: {\n mediaGroups\n },\n mediaTypes: {\n [type]: {\n groups,\n tracks,\n logger_\n }\n },\n mainPlaylistLoader\n } = settings;\n const audioOnlyMain = isAudioOnly(mainPlaylistLoader.main); // force a default if we have none\n\n if (!mediaGroups[type] || Object.keys(mediaGroups[type]).length === 0) {\n mediaGroups[type] = {\n main: {\n default: {\n default: true\n }\n }\n };\n\n if (audioOnlyMain) {\n mediaGroups[type].main.default.playlists = mainPlaylistLoader.main.playlists;\n }\n }\n\n for (const groupId in mediaGroups[type]) {\n if (!groups[groupId]) {\n groups[groupId] = [];\n }\n\n for (const variantLabel in mediaGroups[type][groupId]) {\n let properties = mediaGroups[type][groupId][variantLabel];\n let playlistLoader;\n\n if (audioOnlyMain) {\n logger_(`AUDIO group '${groupId}' label '${variantLabel}' is a main playlist`);\n properties.isMainPlaylist = true;\n playlistLoader = null; // if vhs-json was provided as the source, and the media playlist was resolved,\n // use the resolved media playlist object\n } else if (sourceType === 'vhs-json' && properties.playlists) {\n playlistLoader = new PlaylistLoader(properties.playlists[0], vhs, requestOptions);\n } else if (properties.resolvedUri) {\n playlistLoader = new PlaylistLoader(properties.resolvedUri, vhs, requestOptions); // TODO: dash isn't the only type with properties.playlists\n // should we even have properties.playlists in this check.\n } else if (properties.playlists && sourceType === 'dash') {\n playlistLoader = new DashPlaylistLoader(properties.playlists[0], vhs, requestOptions, mainPlaylistLoader);\n } else {\n // no resolvedUri means the audio is muxed with the video when using this\n // audio track\n playlistLoader = null;\n }\n\n properties = merge({\n id: variantLabel,\n playlistLoader\n }, properties);\n setupListeners[type](type, properties.playlistLoader, settings);\n groups[groupId].push(properties);\n\n if (typeof tracks[variantLabel] === 'undefined') {\n const track = new videojs.AudioTrack({\n id: variantLabel,\n kind: audioTrackKind_(properties),\n enabled: false,\n language: properties.language,\n default: properties.default,\n label: variantLabel\n });\n tracks[variantLabel] = track;\n }\n }\n } // setup single error event handler for the segment loader\n\n\n segmentLoader.on('error', onError[type](type, settings));\n },\n\n /**\n * Setup PlaylistLoaders and TextTracks for the subtitle groups\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @function initialize.SUBTITLES\n */\n 'SUBTITLES': (type, settings) => {\n const {\n tech,\n vhs,\n sourceType,\n segmentLoaders: {\n [type]: segmentLoader\n },\n requestOptions,\n main: {\n mediaGroups\n },\n mediaTypes: {\n [type]: {\n groups,\n tracks\n }\n },\n mainPlaylistLoader\n } = settings;\n\n for (const groupId in mediaGroups[type]) {\n if (!groups[groupId]) {\n groups[groupId] = [];\n }\n\n for (const variantLabel in mediaGroups[type][groupId]) {\n if (!vhs.options_.useForcedSubtitles && mediaGroups[type][groupId][variantLabel].forced) {\n // Subtitle playlists with the forced attribute are not selectable in Safari.\n // According to Apple's HLS Authoring Specification:\n // If content has forced subtitles and regular subtitles in a given language,\n // the regular subtitles track in that language MUST contain both the forced\n // subtitles and the regular subtitles for that language.\n // Because of this requirement and that Safari does not add forced subtitles,\n // forced subtitles are skipped here to maintain consistent experience across\n // all platforms\n continue;\n }\n\n let properties = mediaGroups[type][groupId][variantLabel];\n let playlistLoader;\n\n if (sourceType === 'hls') {\n playlistLoader = new PlaylistLoader(properties.resolvedUri, vhs, requestOptions);\n } else if (sourceType === 'dash') {\n const playlists = properties.playlists.filter(p => p.excludeUntil !== Infinity);\n\n if (!playlists.length) {\n return;\n }\n\n playlistLoader = new DashPlaylistLoader(properties.playlists[0], vhs, requestOptions, mainPlaylistLoader);\n } else if (sourceType === 'vhs-json') {\n playlistLoader = new PlaylistLoader( // if the vhs-json object included the media playlist, use the media playlist\n // as provided, otherwise use the resolved URI to load the playlist\n properties.playlists ? properties.playlists[0] : properties.resolvedUri, vhs, requestOptions);\n }\n\n properties = merge({\n id: variantLabel,\n playlistLoader\n }, properties);\n setupListeners[type](type, properties.playlistLoader, settings);\n groups[groupId].push(properties);\n\n if (typeof tracks[variantLabel] === 'undefined') {\n const track = tech.addRemoteTextTrack({\n id: variantLabel,\n kind: 'subtitles',\n default: properties.default && properties.autoselect,\n language: properties.language,\n label: variantLabel\n }, false).track;\n tracks[variantLabel] = track;\n }\n }\n } // setup single error event handler for the segment loader\n\n\n segmentLoader.on('error', onError[type](type, settings));\n },\n\n /**\n * Setup TextTracks for the closed-caption groups\n *\n * @param {String} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @function initialize['CLOSED-CAPTIONS']\n */\n 'CLOSED-CAPTIONS': (type, settings) => {\n const {\n tech,\n main: {\n mediaGroups\n },\n mediaTypes: {\n [type]: {\n groups,\n tracks\n }\n }\n } = settings;\n\n for (const groupId in mediaGroups[type]) {\n if (!groups[groupId]) {\n groups[groupId] = [];\n }\n\n for (const variantLabel in mediaGroups[type][groupId]) {\n const properties = mediaGroups[type][groupId][variantLabel]; // Look for either 608 (CCn) or 708 (SERVICEn) caption services\n\n if (!/^(?:CC|SERVICE)/.test(properties.instreamId)) {\n continue;\n }\n\n const captionServices = tech.options_.vhs && tech.options_.vhs.captionServices || {};\n let newProps = {\n label: variantLabel,\n language: properties.language,\n instreamId: properties.instreamId,\n default: properties.default && properties.autoselect\n };\n\n if (captionServices[newProps.instreamId]) {\n newProps = merge(newProps, captionServices[newProps.instreamId]);\n }\n\n if (newProps.default === undefined) {\n delete newProps.default;\n } // No PlaylistLoader is required for Closed-Captions because the captions are\n // embedded within the video stream\n\n\n groups[groupId].push(merge({\n id: variantLabel\n }, properties));\n\n if (typeof tracks[variantLabel] === 'undefined') {\n const track = tech.addRemoteTextTrack({\n id: newProps.instreamId,\n kind: 'captions',\n default: newProps.default,\n language: newProps.language,\n label: newProps.label\n }, false).track;\n tracks[variantLabel] = track;\n }\n }\n }\n }\n};\n\nconst groupMatch = (list, media) => {\n for (let i = 0; i < list.length; i++) {\n if (playlistMatch(media, list[i])) {\n return true;\n }\n\n if (list[i].playlists && groupMatch(list[i].playlists, media)) {\n return true;\n }\n }\n\n return false;\n};\n/**\n * Returns a function used to get the active group of the provided type\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Function that returns the active media group for the provided type. Takes an\n * optional parameter {TextTrack} track. If no track is provided, a list of all\n * variants in the group, otherwise the variant corresponding to the provided\n * track is returned.\n * @function activeGroup\n */\n\n\nconst activeGroup = (type, settings) => track => {\n const {\n mainPlaylistLoader,\n mediaTypes: {\n [type]: {\n groups\n }\n }\n } = settings;\n const media = mainPlaylistLoader.media();\n\n if (!media) {\n return null;\n }\n\n let variants = null; // set to variants to main media active group\n\n if (media.attributes[type]) {\n variants = groups[media.attributes[type]];\n }\n\n const groupKeys = Object.keys(groups);\n\n if (!variants) {\n // find the mainPlaylistLoader media\n // that is in a media group if we are dealing\n // with audio only\n if (type === 'AUDIO' && groupKeys.length > 1 && isAudioOnly(settings.main)) {\n for (let i = 0; i < groupKeys.length; i++) {\n const groupPropertyList = groups[groupKeys[i]];\n\n if (groupMatch(groupPropertyList, media)) {\n variants = groupPropertyList;\n break;\n }\n } // use the main group if it exists\n\n } else if (groups.main) {\n variants = groups.main; // only one group, use that one\n } else if (groupKeys.length === 1) {\n variants = groups[groupKeys[0]];\n }\n }\n\n if (typeof track === 'undefined') {\n return variants;\n }\n\n if (track === null || !variants) {\n // An active track was specified so a corresponding group is expected. track === null\n // means no track is currently active so there is no corresponding group\n return null;\n }\n\n return variants.filter(props => props.id === track.id)[0] || null;\n};\nconst activeTrack = {\n /**\n * Returns a function used to get the active track of type provided\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Function that returns the active media track for the provided type. Returns\n * null if no track is active\n * @function activeTrack.AUDIO\n */\n AUDIO: (type, settings) => () => {\n const {\n mediaTypes: {\n [type]: {\n tracks\n }\n }\n } = settings;\n\n for (const id in tracks) {\n if (tracks[id].enabled) {\n return tracks[id];\n }\n }\n\n return null;\n },\n\n /**\n * Returns a function used to get the active track of type provided\n *\n * @param {string} type\n * MediaGroup type\n * @param {Object} settings\n * Object containing required information for media groups\n * @return {Function}\n * Function that returns the active media track for the provided type. Returns\n * null if no track is active\n * @function activeTrack.SUBTITLES\n */\n SUBTITLES: (type, settings) => () => {\n const {\n mediaTypes: {\n [type]: {\n tracks\n }\n }\n } = settings;\n\n for (const id in tracks) {\n if (tracks[id].mode === 'showing' || tracks[id].mode === 'hidden') {\n return tracks[id];\n }\n }\n\n return null;\n }\n};\nconst getActiveGroup = (type, {\n mediaTypes\n}) => () => {\n const activeTrack_ = mediaTypes[type].activeTrack();\n\n if (!activeTrack_) {\n return null;\n }\n\n return mediaTypes[type].activeGroup(activeTrack_);\n};\n/**\n * Setup PlaylistLoaders and Tracks for media groups (Audio, Subtitles,\n * Closed-Captions) specified in the main manifest.\n *\n * @param {Object} settings\n * Object containing required information for setting up the media groups\n * @param {Tech} settings.tech\n * The tech of the player\n * @param {Object} settings.requestOptions\n * XHR request options used by the segment loaders\n * @param {PlaylistLoader} settings.mainPlaylistLoader\n * PlaylistLoader for the main source\n * @param {VhsHandler} settings.vhs\n * VHS SourceHandler\n * @param {Object} settings.main\n * The parsed main manifest\n * @param {Object} settings.mediaTypes\n * Object to store the loaders, tracks, and utility methods for each media type\n * @param {Function} settings.excludePlaylist\n * Excludes the current rendition and forces a rendition switch.\n * @function setupMediaGroups\n */\n\nconst setupMediaGroups = settings => {\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(type => {\n initialize[type](type, settings);\n });\n const {\n mediaTypes,\n mainPlaylistLoader,\n tech,\n vhs,\n segmentLoaders: {\n ['AUDIO']: audioSegmentLoader,\n main: mainSegmentLoader\n }\n } = settings; // setup active group and track getters and change event handlers\n\n ['AUDIO', 'SUBTITLES'].forEach(type => {\n mediaTypes[type].activeGroup = activeGroup(type, settings);\n mediaTypes[type].activeTrack = activeTrack[type](type, settings);\n mediaTypes[type].onGroupChanged = onGroupChanged(type, settings);\n mediaTypes[type].onGroupChanging = onGroupChanging(type, settings);\n mediaTypes[type].onTrackChanged = onTrackChanged(type, settings);\n mediaTypes[type].getActiveGroup = getActiveGroup(type, settings);\n }); // DO NOT enable the default subtitle or caption track.\n // DO enable the default audio track\n\n const audioGroup = mediaTypes.AUDIO.activeGroup();\n\n if (audioGroup) {\n const groupId = (audioGroup.filter(group => group.default)[0] || audioGroup[0]).id;\n mediaTypes.AUDIO.tracks[groupId].enabled = true;\n mediaTypes.AUDIO.onGroupChanged();\n mediaTypes.AUDIO.onTrackChanged();\n const activeAudioGroup = mediaTypes.AUDIO.getActiveGroup(); // a similar check for handling setAudio on each loader is run again each time the\n // track is changed, but needs to be handled here since the track may not be considered\n // changed on the first call to onTrackChanged\n\n if (!activeAudioGroup.playlistLoader) {\n // either audio is muxed with video or the stream is audio only\n mainSegmentLoader.setAudio(true);\n } else {\n // audio is demuxed\n mainSegmentLoader.setAudio(false);\n audioSegmentLoader.setAudio(true);\n }\n }\n\n mainPlaylistLoader.on('mediachange', () => {\n ['AUDIO', 'SUBTITLES'].forEach(type => mediaTypes[type].onGroupChanged());\n });\n mainPlaylistLoader.on('mediachanging', () => {\n ['AUDIO', 'SUBTITLES'].forEach(type => mediaTypes[type].onGroupChanging());\n }); // custom audio track change event handler for usage event\n\n const onAudioTrackChanged = () => {\n mediaTypes.AUDIO.onTrackChanged();\n tech.trigger({\n type: 'usage',\n name: 'vhs-audio-change'\n });\n };\n\n tech.audioTracks().addEventListener('change', onAudioTrackChanged);\n tech.remoteTextTracks().addEventListener('change', mediaTypes.SUBTITLES.onTrackChanged);\n vhs.on('dispose', () => {\n tech.audioTracks().removeEventListener('change', onAudioTrackChanged);\n tech.remoteTextTracks().removeEventListener('change', mediaTypes.SUBTITLES.onTrackChanged);\n }); // clear existing audio tracks and add the ones we just created\n\n tech.clearTracks('audio');\n\n for (const id in mediaTypes.AUDIO.tracks) {\n tech.audioTracks().addTrack(mediaTypes.AUDIO.tracks[id]);\n }\n};\n/**\n * Creates skeleton object used to store the loaders, tracks, and utility methods for each\n * media type\n *\n * @return {Object}\n * Object to store the loaders, tracks, and utility methods for each media type\n * @function createMediaTypes\n */\n\nconst createMediaTypes = () => {\n const mediaTypes = {};\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(type => {\n mediaTypes[type] = {\n groups: {},\n tracks: {},\n activePlaylistLoader: null,\n activeGroup: noop,\n activeTrack: noop,\n getActiveGroup: noop,\n onGroupChanged: noop,\n onTrackChanged: noop,\n lastTrack_: null,\n logger_: logger(`MediaGroups[${type}]`)\n };\n });\n return mediaTypes;\n};\n\n/**\n * A utility class for setting properties and maintaining the state of the content steering manifest.\n *\n * Content Steering manifest format:\n * VERSION: number (required) currently only version 1 is supported.\n * TTL: number in seconds (optional) until the next content steering manifest reload.\n * RELOAD-URI: string (optional) uri to fetch the next content steering manifest.\n * SERVICE-LOCATION-PRIORITY or PATHWAY-PRIORITY a non empty array of unique string values.\n * PATHWAY-CLONES: array (optional) (HLS only) pathway clone objects to copy from other playlists.\n */\n\nclass SteeringManifest {\n constructor() {\n this.priority_ = [];\n this.pathwayClones_ = new Map();\n }\n\n set version(number) {\n // Only version 1 is currently supported for both DASH and HLS.\n if (number === 1) {\n this.version_ = number;\n }\n }\n\n set ttl(seconds) {\n // TTL = time-to-live, default = 300 seconds.\n this.ttl_ = seconds || 300;\n }\n\n set reloadUri(uri) {\n if (uri) {\n // reload URI can be relative to the previous reloadUri.\n this.reloadUri_ = resolveUrl(this.reloadUri_, uri);\n }\n }\n\n set priority(array) {\n // priority must be non-empty and unique values.\n if (array && array.length) {\n this.priority_ = array;\n }\n }\n\n set pathwayClones(array) {\n // pathwayClones must be non-empty.\n if (array && array.length) {\n this.pathwayClones_ = new Map(array.map(clone => [clone.ID, clone]));\n }\n }\n\n get version() {\n return this.version_;\n }\n\n get ttl() {\n return this.ttl_;\n }\n\n get reloadUri() {\n return this.reloadUri_;\n }\n\n get priority() {\n return this.priority_;\n }\n\n get pathwayClones() {\n return this.pathwayClones_;\n }\n\n}\n/**\n * This class represents a content steering manifest and associated state. See both HLS and DASH specifications.\n * HLS: https://developer.apple.com/streaming/HLSContentSteeringSpecification.pdf and\n * https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/ section 4.4.6.6.\n * DASH: https://dashif.org/docs/DASH-IF-CTS-00XX-Content-Steering-Community-Review.pdf\n *\n * @param {function} xhr for making a network request from the browser.\n * @param {function} bandwidth for fetching the current bandwidth from the main segment loader.\n */\n\n\nclass ContentSteeringController extends videojs.EventTarget {\n constructor(xhr, bandwidth) {\n super();\n this.currentPathway = null;\n this.defaultPathway = null;\n this.queryBeforeStart = false;\n this.availablePathways_ = new Set();\n this.steeringManifest = new SteeringManifest();\n this.proxyServerUrl_ = null;\n this.manifestType_ = null;\n this.ttlTimeout_ = null;\n this.request_ = null;\n this.currentPathwayClones = new Map();\n this.nextPathwayClones = new Map();\n this.excludedSteeringManifestURLs = new Set();\n this.logger_ = logger('Content Steering');\n this.xhr_ = xhr;\n this.getBandwidth_ = bandwidth;\n }\n /**\n * Assigns the content steering tag properties to the steering controller\n *\n * @param {string} baseUrl the baseURL from the main manifest for resolving the steering manifest url\n * @param {Object} steeringTag the content steering tag from the main manifest\n */\n\n\n assignTagProperties(baseUrl, steeringTag) {\n this.manifestType_ = steeringTag.serverUri ? 'HLS' : 'DASH'; // serverUri is HLS serverURL is DASH\n\n const steeringUri = steeringTag.serverUri || steeringTag.serverURL;\n\n if (!steeringUri) {\n this.logger_(`steering manifest URL is ${steeringUri}, cannot request steering manifest.`);\n this.trigger('error');\n return;\n } // Content steering manifests can be encoded as a data URI. We can decode, parse and return early if that's the case.\n\n\n if (steeringUri.startsWith('data:')) {\n this.decodeDataUriManifest_(steeringUri.substring(steeringUri.indexOf(',') + 1));\n return;\n } // reloadUri is the resolution of the main manifest URL and steering URL.\n\n\n this.steeringManifest.reloadUri = resolveUrl(baseUrl, steeringUri); // pathwayId is HLS defaultServiceLocation is DASH\n\n this.defaultPathway = steeringTag.pathwayId || steeringTag.defaultServiceLocation; // currently only DASH supports the following properties on tags.\n\n this.queryBeforeStart = steeringTag.queryBeforeStart;\n this.proxyServerUrl_ = steeringTag.proxyServerURL; // trigger a steering event if we have a pathway from the content steering tag.\n // this tells VHS which segment pathway to start with.\n // If queryBeforeStart is true we need to wait for the steering manifest response.\n\n if (this.defaultPathway && !this.queryBeforeStart) {\n this.trigger('content-steering');\n }\n }\n /**\n * Requests the content steering manifest and parse the response. This should only be called after\n * assignTagProperties was called with a content steering tag.\n *\n * @param {string} initialUri The optional uri to make the request with.\n * If set, the request should be made with exactly what is passed in this variable.\n * This scenario should only happen once on initalization.\n */\n\n\n requestSteeringManifest(initial) {\n const reloadUri = this.steeringManifest.reloadUri;\n\n if (!reloadUri) {\n return;\n } // We currently don't support passing MPD query parameters directly to the content steering URL as this requires\n // ExtUrlQueryInfo tag support. See the DASH content steering spec section 8.1.\n // This request URI accounts for manifest URIs that have been excluded.\n\n\n const uri = initial ? reloadUri : this.getRequestURI(reloadUri); // If there are no valid manifest URIs, we should stop content steering.\n\n if (!uri) {\n this.logger_('No valid content steering manifest URIs. Stopping content steering.');\n this.trigger('error');\n this.dispose();\n return;\n }\n\n const metadata = {\n contentSteeringInfo: {\n uri\n }\n };\n this.trigger({\n type: 'contentsteeringloadstart',\n metadata\n });\n this.request_ = this.xhr_({\n uri,\n requestType: 'content-steering-manifest'\n }, (error, errorInfo) => {\n if (error) {\n // If the client receives HTTP 410 Gone in response to a manifest request,\n // it MUST NOT issue another request for that URI for the remainder of the\n // playback session. It MAY continue to use the most-recently obtained set\n // of Pathways.\n if (errorInfo.status === 410) {\n this.logger_(`manifest request 410 ${error}.`);\n this.logger_(`There will be no more content steering requests to ${uri} this session.`);\n this.excludedSteeringManifestURLs.add(uri);\n return;\n } // If the client receives HTTP 429 Too Many Requests with a Retry-After\n // header in response to a manifest request, it SHOULD wait until the time\n // specified by the Retry-After header to reissue the request.\n\n\n if (errorInfo.status === 429) {\n const retrySeconds = errorInfo.responseHeaders['retry-after'];\n this.logger_(`manifest request 429 ${error}.`);\n this.logger_(`content steering will retry in ${retrySeconds} seconds.`);\n this.startTTLTimeout_(parseInt(retrySeconds, 10));\n return;\n } // If the Steering Manifest cannot be loaded and parsed correctly, the\n // client SHOULD continue to use the previous values and attempt to reload\n // it after waiting for the previously-specified TTL (or 5 minutes if\n // none).\n\n\n this.logger_(`manifest failed to load ${error}.`);\n this.startTTLTimeout_();\n return;\n }\n\n this.trigger({\n type: 'contentsteeringloadcomplete',\n metadata\n });\n let steeringManifestJson;\n\n try {\n steeringManifestJson = JSON.parse(this.request_.responseText);\n } catch (parseError) {\n const errorMetadata = {\n errorType: videojs.Error.StreamingContentSteeringParserError,\n error: parseError\n };\n this.trigger({\n type: 'error',\n metadata: errorMetadata\n });\n }\n\n this.assignSteeringProperties_(steeringManifestJson);\n const parsedMetadata = {\n contentSteeringInfo: metadata.contentSteeringInfo,\n contentSteeringManifest: {\n version: this.steeringManifest.version,\n reloadUri: this.steeringManifest.reloadUri,\n priority: this.steeringManifest.priority\n }\n };\n this.trigger({\n type: 'contentsteeringparsed',\n metadata: parsedMetadata\n });\n this.startTTLTimeout_();\n });\n }\n /**\n * Set the proxy server URL and add the steering manifest url as a URI encoded parameter.\n *\n * @param {string} steeringUrl the steering manifest url\n * @return the steering manifest url to a proxy server with all parameters set\n */\n\n\n setProxyServerUrl_(steeringUrl) {\n const steeringUrlObject = new window$1.URL(steeringUrl);\n const proxyServerUrlObject = new window$1.URL(this.proxyServerUrl_);\n proxyServerUrlObject.searchParams.set('url', encodeURI(steeringUrlObject.toString()));\n return this.setSteeringParams_(proxyServerUrlObject.toString());\n }\n /**\n * Decodes and parses the data uri encoded steering manifest\n *\n * @param {string} dataUri the data uri to be decoded and parsed.\n */\n\n\n decodeDataUriManifest_(dataUri) {\n const steeringManifestJson = JSON.parse(window$1.atob(dataUri));\n this.assignSteeringProperties_(steeringManifestJson);\n }\n /**\n * Set the HLS or DASH content steering manifest request query parameters. For example:\n * _HLS_pathway=\"\" and _HLS_throughput=\n * _DASH_pathway and _DASH_throughput\n *\n * @param {string} uri to add content steering server parameters to.\n * @return a new uri as a string with the added steering query parameters.\n */\n\n\n setSteeringParams_(url) {\n const urlObject = new window$1.URL(url);\n const path = this.getPathway();\n const networkThroughput = this.getBandwidth_();\n\n if (path) {\n const pathwayKey = `_${this.manifestType_}_pathway`;\n urlObject.searchParams.set(pathwayKey, path);\n }\n\n if (networkThroughput) {\n const throughputKey = `_${this.manifestType_}_throughput`;\n urlObject.searchParams.set(throughputKey, networkThroughput);\n }\n\n return urlObject.toString();\n }\n /**\n * Assigns the current steering manifest properties and to the SteeringManifest object\n *\n * @param {Object} steeringJson the raw JSON steering manifest\n */\n\n\n assignSteeringProperties_(steeringJson) {\n this.steeringManifest.version = steeringJson.VERSION;\n\n if (!this.steeringManifest.version) {\n this.logger_(`manifest version is ${steeringJson.VERSION}, which is not supported.`);\n this.trigger('error');\n return;\n }\n\n this.steeringManifest.ttl = steeringJson.TTL;\n this.steeringManifest.reloadUri = steeringJson['RELOAD-URI']; // HLS = PATHWAY-PRIORITY required. DASH = SERVICE-LOCATION-PRIORITY optional\n\n this.steeringManifest.priority = steeringJson['PATHWAY-PRIORITY'] || steeringJson['SERVICE-LOCATION-PRIORITY']; // Pathway clones to be created/updated in HLS.\n // See section 7.2 https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/\n\n this.steeringManifest.pathwayClones = steeringJson['PATHWAY-CLONES'];\n this.nextPathwayClones = this.steeringManifest.pathwayClones; // 1. apply first pathway from the array.\n // 2. if first pathway doesn't exist in manifest, try next pathway.\n // a. if all pathways are exhausted, ignore the steering manifest priority.\n // 3. if segments fail from an established pathway, try all variants/renditions, then exclude the failed pathway.\n // a. exclude a pathway for a minimum of the last TTL duration. Meaning, from the next steering response,\n // the excluded pathway will be ignored.\n // See excludePathway usage in excludePlaylist().\n // If there are no available pathways, we need to stop content steering.\n\n if (!this.availablePathways_.size) {\n this.logger_('There are no available pathways for content steering. Ending content steering.');\n this.trigger('error');\n this.dispose();\n }\n\n const chooseNextPathway = pathwaysByPriority => {\n for (const path of pathwaysByPriority) {\n if (this.availablePathways_.has(path)) {\n return path;\n }\n } // If no pathway matches, ignore the manifest and choose the first available.\n\n\n return [...this.availablePathways_][0];\n };\n\n const nextPathway = chooseNextPathway(this.steeringManifest.priority);\n\n if (this.currentPathway !== nextPathway) {\n this.currentPathway = nextPathway;\n this.trigger('content-steering');\n }\n }\n /**\n * Returns the pathway to use for steering decisions\n *\n * @return {string} returns the current pathway or the default\n */\n\n\n getPathway() {\n return this.currentPathway || this.defaultPathway;\n }\n /**\n * Chooses the manifest request URI based on proxy URIs and server URLs.\n * Also accounts for exclusion on certain manifest URIs.\n *\n * @param {string} reloadUri the base uri before parameters\n *\n * @return {string} the final URI for the request to the manifest server.\n */\n\n\n getRequestURI(reloadUri) {\n if (!reloadUri) {\n return null;\n }\n\n const isExcluded = uri => this.excludedSteeringManifestURLs.has(uri);\n\n if (this.proxyServerUrl_) {\n const proxyURI = this.setProxyServerUrl_(reloadUri);\n\n if (!isExcluded(proxyURI)) {\n return proxyURI;\n }\n }\n\n const steeringURI = this.setSteeringParams_(reloadUri);\n\n if (!isExcluded(steeringURI)) {\n return steeringURI;\n } // Return nothing if all valid manifest URIs are excluded.\n\n\n return null;\n }\n /**\n * Start the timeout for re-requesting the steering manifest at the TTL interval.\n *\n * @param {number} ttl time in seconds of the timeout. Defaults to the\n * ttl interval in the steering manifest\n */\n\n\n startTTLTimeout_(ttl = this.steeringManifest.ttl) {\n // 300 (5 minutes) is the default value.\n const ttlMS = ttl * 1000;\n this.ttlTimeout_ = window$1.setTimeout(() => {\n this.requestSteeringManifest();\n }, ttlMS);\n }\n /**\n * Clear the TTL timeout if necessary.\n */\n\n\n clearTTLTimeout_() {\n window$1.clearTimeout(this.ttlTimeout_);\n this.ttlTimeout_ = null;\n }\n /**\n * aborts any current steering xhr and sets the current request object to null\n */\n\n\n abort() {\n if (this.request_) {\n this.request_.abort();\n }\n\n this.request_ = null;\n }\n /**\n * aborts steering requests clears the ttl timeout and resets all properties.\n */\n\n\n dispose() {\n this.off('content-steering');\n this.off('error');\n this.abort();\n this.clearTTLTimeout_();\n this.currentPathway = null;\n this.defaultPathway = null;\n this.queryBeforeStart = null;\n this.proxyServerUrl_ = null;\n this.manifestType_ = null;\n this.ttlTimeout_ = null;\n this.request_ = null;\n this.excludedSteeringManifestURLs = new Set();\n this.availablePathways_ = new Set();\n this.steeringManifest = new SteeringManifest();\n }\n /**\n * adds a pathway to the available pathways set\n *\n * @param {string} pathway the pathway string to add\n */\n\n\n addAvailablePathway(pathway) {\n if (pathway) {\n this.availablePathways_.add(pathway);\n }\n }\n /**\n * Clears all pathways from the available pathways set\n */\n\n\n clearAvailablePathways() {\n this.availablePathways_.clear();\n }\n /**\n * Removes a pathway from the available pathways set.\n */\n\n\n excludePathway(pathway) {\n return this.availablePathways_.delete(pathway);\n }\n /**\n * Checks the refreshed DASH manifest content steering tag for changes.\n *\n * @param {string} baseURL new steering tag on DASH manifest refresh\n * @param {Object} newTag the new tag to check for changes\n * @return a true or false whether the new tag has different values\n */\n\n\n didDASHTagChange(baseURL, newTag) {\n return !newTag && this.steeringManifest.reloadUri || newTag && (resolveUrl(baseURL, newTag.serverURL) !== this.steeringManifest.reloadUri || newTag.defaultServiceLocation !== this.defaultPathway || newTag.queryBeforeStart !== this.queryBeforeStart || newTag.proxyServerURL !== this.proxyServerUrl_);\n }\n\n getAvailablePathways() {\n return this.availablePathways_;\n }\n\n}\n\nconst debounce = (callback, wait) => {\n let timeoutId = null;\n return (...args) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n callback.apply(null, args);\n }, wait);\n };\n};\n\nconst ABORT_EARLY_EXCLUSION_SECONDS = 10;\nlet Vhs$1; // SegmentLoader stats that need to have each loader's\n// values summed to calculate the final value\n\nconst loaderStats = ['mediaRequests', 'mediaRequestsAborted', 'mediaRequestsTimedout', 'mediaRequestsErrored', 'mediaTransferDuration', 'mediaBytesTransferred', 'mediaAppends'];\n\nconst sumLoaderStat = function (stat) {\n return this.audioSegmentLoader_[stat] + this.mainSegmentLoader_[stat];\n};\n\nconst shouldSwitchToMedia = function ({\n currentPlaylist,\n buffered,\n currentTime,\n nextPlaylist,\n bufferLowWaterLine,\n bufferHighWaterLine,\n duration,\n bufferBasedABR,\n log\n}) {\n // we have no other playlist to switch to\n if (!nextPlaylist) {\n videojs.log.warn('We received no playlist to switch to. Please check your stream.');\n return false;\n }\n\n const sharedLogLine = `allowing switch ${currentPlaylist && currentPlaylist.id || 'null'} -> ${nextPlaylist.id}`;\n\n if (!currentPlaylist) {\n log(`${sharedLogLine} as current playlist is not set`);\n return true;\n } // no need to switch if playlist is the same\n\n\n if (nextPlaylist.id === currentPlaylist.id) {\n return false;\n } // determine if current time is in a buffered range.\n\n\n const isBuffered = Boolean(findRange(buffered, currentTime).length); // If the playlist is live, then we want to not take low water line into account.\n // This is because in LIVE, the player plays 3 segments from the end of the\n // playlist, and if `BUFFER_LOW_WATER_LINE` is greater than the duration availble\n // in those segments, a viewer will never experience a rendition upswitch.\n\n if (!currentPlaylist.endList) {\n // For LLHLS live streams, don't switch renditions before playback has started, as it almost\n // doubles the time to first playback.\n if (!isBuffered && typeof currentPlaylist.partTargetDuration === 'number') {\n log(`not ${sharedLogLine} as current playlist is live llhls, but currentTime isn't in buffered.`);\n return false;\n }\n\n log(`${sharedLogLine} as current playlist is live`);\n return true;\n }\n\n const forwardBuffer = timeAheadOf(buffered, currentTime);\n const maxBufferLowWaterLine = bufferBasedABR ? Config.EXPERIMENTAL_MAX_BUFFER_LOW_WATER_LINE : Config.MAX_BUFFER_LOW_WATER_LINE; // For the same reason as LIVE, we ignore the low water line when the VOD\n // duration is below the max potential low water line\n\n if (duration < maxBufferLowWaterLine) {\n log(`${sharedLogLine} as duration < max low water line (${duration} < ${maxBufferLowWaterLine})`);\n return true;\n }\n\n const nextBandwidth = nextPlaylist.attributes.BANDWIDTH;\n const currBandwidth = currentPlaylist.attributes.BANDWIDTH; // when switching down, if our buffer is lower than the high water line,\n // we can switch down\n\n if (nextBandwidth < currBandwidth && (!bufferBasedABR || forwardBuffer < bufferHighWaterLine)) {\n let logLine = `${sharedLogLine} as next bandwidth < current bandwidth (${nextBandwidth} < ${currBandwidth})`;\n\n if (bufferBasedABR) {\n logLine += ` and forwardBuffer < bufferHighWaterLine (${forwardBuffer} < ${bufferHighWaterLine})`;\n }\n\n log(logLine);\n return true;\n } // and if our buffer is higher than the low water line,\n // we can switch up\n\n\n if ((!bufferBasedABR || nextBandwidth > currBandwidth) && forwardBuffer >= bufferLowWaterLine) {\n let logLine = `${sharedLogLine} as forwardBuffer >= bufferLowWaterLine (${forwardBuffer} >= ${bufferLowWaterLine})`;\n\n if (bufferBasedABR) {\n logLine += ` and next bandwidth > current bandwidth (${nextBandwidth} > ${currBandwidth})`;\n }\n\n log(logLine);\n return true;\n }\n\n log(`not ${sharedLogLine} as no switching criteria met`);\n return false;\n};\n/**\n * the main playlist controller controller all interactons\n * between playlists and segmentloaders. At this time this mainly\n * involves a main playlist and a series of audio playlists\n * if they are available\n *\n * @class PlaylistController\n * @extends videojs.EventTarget\n */\n\n\nclass PlaylistController extends videojs.EventTarget {\n constructor(options) {\n super(); // Adding a slight debounce to avoid duplicate calls during rapid quality changes, for example:\n // When selecting quality from the quality list,\n // where we may have multiple bandwidth profiles for the same vertical resolution.\n\n this.fastQualityChange_ = debounce(this.fastQualityChange_.bind(this), 100);\n const {\n src,\n withCredentials,\n tech,\n bandwidth,\n externVhs,\n useCueTags,\n playlistExclusionDuration,\n enableLowInitialPlaylist,\n sourceType,\n cacheEncryptionKeys,\n bufferBasedABR,\n leastPixelDiffSelector,\n captionServices,\n experimentalUseMMS\n } = options;\n\n if (!src) {\n throw new Error('A non-empty playlist URL or JSON manifest string is required');\n }\n\n let {\n maxPlaylistRetries\n } = options;\n\n if (maxPlaylistRetries === null || typeof maxPlaylistRetries === 'undefined') {\n maxPlaylistRetries = Infinity;\n }\n\n Vhs$1 = externVhs;\n this.bufferBasedABR = Boolean(bufferBasedABR);\n this.leastPixelDiffSelector = Boolean(leastPixelDiffSelector);\n this.withCredentials = withCredentials;\n this.tech_ = tech;\n this.vhs_ = tech.vhs;\n this.player_ = options.player_;\n this.sourceType_ = sourceType;\n this.useCueTags_ = useCueTags;\n this.playlistExclusionDuration = playlistExclusionDuration;\n this.maxPlaylistRetries = maxPlaylistRetries;\n this.enableLowInitialPlaylist = enableLowInitialPlaylist;\n this.usingManagedMediaSource_ = false;\n\n if (this.useCueTags_) {\n this.cueTagsTrack_ = this.tech_.addTextTrack('metadata', 'ad-cues');\n this.cueTagsTrack_.inBandMetadataTrackDispatchType = '';\n }\n\n this.requestOptions_ = {\n withCredentials,\n maxPlaylistRetries,\n timeout: null\n };\n this.on('error', this.pauseLoading);\n this.mediaTypes_ = createMediaTypes();\n\n if (experimentalUseMMS && window$1.ManagedMediaSource) {\n // Airplay source not yet implemented. Remote playback must be disabled.\n this.tech_.el_.disableRemotePlayback = true;\n this.mediaSource = new window$1.ManagedMediaSource();\n this.usingManagedMediaSource_ = true;\n videojs.log('Using ManagedMediaSource');\n } else if (window$1.MediaSource) {\n this.mediaSource = new window$1.MediaSource();\n }\n\n this.handleDurationChange_ = this.handleDurationChange_.bind(this);\n this.handleSourceOpen_ = this.handleSourceOpen_.bind(this);\n this.handleSourceEnded_ = this.handleSourceEnded_.bind(this);\n this.load = this.load.bind(this);\n this.pause = this.pause.bind(this);\n this.mediaSource.addEventListener('durationchange', this.handleDurationChange_); // load the media source into the player\n\n this.mediaSource.addEventListener('sourceopen', this.handleSourceOpen_);\n this.mediaSource.addEventListener('sourceended', this.handleSourceEnded_);\n this.mediaSource.addEventListener('startstreaming', this.load);\n this.mediaSource.addEventListener('endstreaming', this.pause); // we don't have to handle sourceclose since dispose will handle termination of\n // everything, and the MediaSource should not be detached without a proper disposal\n\n this.seekable_ = createTimeRanges();\n this.hasPlayed_ = false;\n this.syncController_ = new SyncController(options);\n this.segmentMetadataTrack_ = tech.addRemoteTextTrack({\n kind: 'metadata',\n label: 'segment-metadata'\n }, false).track;\n this.decrypter_ = new Decrypter();\n this.sourceUpdater_ = new SourceUpdater(this.mediaSource);\n this.inbandTextTracks_ = {};\n this.timelineChangeController_ = new TimelineChangeController();\n this.keyStatusMap_ = new Map();\n const segmentLoaderSettings = {\n vhs: this.vhs_,\n parse708captions: options.parse708captions,\n useDtsForTimestampOffset: options.useDtsForTimestampOffset,\n captionServices,\n mediaSource: this.mediaSource,\n currentTime: this.tech_.currentTime.bind(this.tech_),\n seekable: () => this.seekable(),\n seeking: () => this.tech_.seeking(),\n duration: () => this.duration(),\n hasPlayed: () => this.hasPlayed_,\n goalBufferLength: () => this.goalBufferLength(),\n bandwidth,\n syncController: this.syncController_,\n decrypter: this.decrypter_,\n sourceType: this.sourceType_,\n inbandTextTracks: this.inbandTextTracks_,\n cacheEncryptionKeys,\n sourceUpdater: this.sourceUpdater_,\n timelineChangeController: this.timelineChangeController_,\n exactManifestTimings: options.exactManifestTimings,\n addMetadataToTextTrack: this.addMetadataToTextTrack.bind(this)\n }; // The source type check not only determines whether a special DASH playlist loader\n // should be used, but also covers the case where the provided src is a vhs-json\n // manifest object (instead of a URL). In the case of vhs-json, the default\n // PlaylistLoader should be used.\n\n this.mainPlaylistLoader_ = this.sourceType_ === 'dash' ? new DashPlaylistLoader(src, this.vhs_, merge(this.requestOptions_, {\n addMetadataToTextTrack: this.addMetadataToTextTrack.bind(this)\n })) : new PlaylistLoader(src, this.vhs_, merge(this.requestOptions_, {\n addDateRangesToTextTrack: this.addDateRangesToTextTrack_.bind(this)\n }));\n this.setupMainPlaylistLoaderListeners_(); // setup segment loaders\n // combined audio/video or just video when alternate audio track is selected\n\n this.mainSegmentLoader_ = new SegmentLoader(merge(segmentLoaderSettings, {\n segmentMetadataTrack: this.segmentMetadataTrack_,\n loaderType: 'main'\n }), options); // alternate audio track\n\n this.audioSegmentLoader_ = new SegmentLoader(merge(segmentLoaderSettings, {\n loaderType: 'audio'\n }), options);\n this.subtitleSegmentLoader_ = new VTTSegmentLoader(merge(segmentLoaderSettings, {\n loaderType: 'vtt',\n featuresNativeTextTracks: this.tech_.featuresNativeTextTracks,\n loadVttJs: () => new Promise((resolve, reject) => {\n function onLoad() {\n tech.off('vttjserror', onError);\n resolve();\n }\n\n function onError() {\n tech.off('vttjsloaded', onLoad);\n reject();\n }\n\n tech.one('vttjsloaded', onLoad);\n tech.one('vttjserror', onError); // safe to call multiple times, script will be loaded only once:\n\n tech.addWebVttScript_();\n })\n }), options);\n\n const getBandwidth = () => {\n return this.mainSegmentLoader_.bandwidth;\n };\n\n this.contentSteeringController_ = new ContentSteeringController(this.vhs_.xhr, getBandwidth);\n this.setupSegmentLoaderListeners_();\n\n if (this.bufferBasedABR) {\n this.mainPlaylistLoader_.one('loadedplaylist', () => this.startABRTimer_());\n this.tech_.on('pause', () => this.stopABRTimer_());\n this.tech_.on('play', () => this.startABRTimer_());\n } // Create SegmentLoader stat-getters\n // mediaRequests_\n // mediaRequestsAborted_\n // mediaRequestsTimedout_\n // mediaRequestsErrored_\n // mediaTransferDuration_\n // mediaBytesTransferred_\n // mediaAppends_\n\n\n loaderStats.forEach(stat => {\n this[stat + '_'] = sumLoaderStat.bind(this, stat);\n });\n this.logger_ = logger('pc');\n this.triggeredFmp4Usage = false;\n\n if (this.tech_.preload() === 'none') {\n this.loadOnPlay_ = () => {\n this.loadOnPlay_ = null;\n this.mainPlaylistLoader_.load();\n };\n\n this.tech_.one('play', this.loadOnPlay_);\n } else {\n this.mainPlaylistLoader_.load();\n }\n\n this.timeToLoadedData__ = -1;\n this.mainAppendsToLoadedData__ = -1;\n this.audioAppendsToLoadedData__ = -1;\n const event = this.tech_.preload() === 'none' ? 'play' : 'loadstart'; // start the first frame timer on loadstart or play (for preload none)\n\n this.tech_.one(event, () => {\n const timeToLoadedDataStart = Date.now();\n this.tech_.one('loadeddata', () => {\n this.timeToLoadedData__ = Date.now() - timeToLoadedDataStart;\n this.mainAppendsToLoadedData__ = this.mainSegmentLoader_.mediaAppends;\n this.audioAppendsToLoadedData__ = this.audioSegmentLoader_.mediaAppends;\n });\n });\n }\n\n mainAppendsToLoadedData_() {\n return this.mainAppendsToLoadedData__;\n }\n\n audioAppendsToLoadedData_() {\n return this.audioAppendsToLoadedData__;\n }\n\n appendsToLoadedData_() {\n const main = this.mainAppendsToLoadedData_();\n const audio = this.audioAppendsToLoadedData_();\n\n if (main === -1 || audio === -1) {\n return -1;\n }\n\n return main + audio;\n }\n\n timeToLoadedData_() {\n return this.timeToLoadedData__;\n }\n /**\n * Run selectPlaylist and switch to the new playlist if we should\n *\n * @param {string} [reason=abr] a reason for why the ABR check is made\n * @private\n */\n\n\n checkABR_(reason = 'abr') {\n const nextPlaylist = this.selectPlaylist();\n\n if (nextPlaylist && this.shouldSwitchToMedia_(nextPlaylist)) {\n this.switchMedia_(nextPlaylist, reason);\n }\n }\n\n switchMedia_(playlist, cause, delay) {\n const oldMedia = this.media();\n const oldId = oldMedia && (oldMedia.id || oldMedia.uri);\n const newId = playlist && (playlist.id || playlist.uri);\n\n if (oldId && oldId !== newId) {\n this.logger_(`switch media ${oldId} -> ${newId} from ${cause}`);\n const metadata = {\n renditionInfo: {\n id: newId,\n bandwidth: playlist.attributes.BANDWIDTH,\n resolution: playlist.attributes.RESOLUTION,\n codecs: playlist.attributes.CODECS\n },\n cause\n };\n this.trigger({\n type: 'renditionselected',\n metadata\n });\n this.tech_.trigger({\n type: 'usage',\n name: `vhs-rendition-change-${cause}`\n });\n }\n\n this.mainPlaylistLoader_.media(playlist, delay);\n }\n /**\n * A function that ensures we switch our playlists inside of `mediaTypes`\n * to match the current `serviceLocation` provided by the contentSteering controller.\n * We want to check media types of `AUDIO`, `SUBTITLES`, and `CLOSED-CAPTIONS`.\n *\n * This should only be called on a DASH playback scenario while using content steering.\n * This is necessary due to differences in how media in HLS manifests are generally tied to\n * a video playlist, where in DASH that is not always the case.\n */\n\n\n switchMediaForDASHContentSteering_() {\n ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(type => {\n const mediaType = this.mediaTypes_[type];\n const activeGroup = mediaType ? mediaType.activeGroup() : null;\n const pathway = this.contentSteeringController_.getPathway();\n\n if (activeGroup && pathway) {\n // activeGroup can be an array or a single group\n const mediaPlaylists = activeGroup.length ? activeGroup[0].playlists : activeGroup.playlists;\n const dashMediaPlaylists = mediaPlaylists.filter(p => p.attributes.serviceLocation === pathway); // Switch the current active playlist to the correct CDN\n\n if (dashMediaPlaylists.length) {\n this.mediaTypes_[type].activePlaylistLoader.media(dashMediaPlaylists[0]);\n }\n }\n });\n }\n /**\n * Start a timer that periodically calls checkABR_\n *\n * @private\n */\n\n\n startABRTimer_() {\n this.stopABRTimer_();\n this.abrTimer_ = window$1.setInterval(() => this.checkABR_(), 250);\n }\n /**\n * Stop the timer that periodically calls checkABR_\n *\n * @private\n */\n\n\n stopABRTimer_() {\n // if we're scrubbing, we don't need to pause.\n // This getter will be added to Video.js in version 7.11.\n if (this.tech_.scrubbing && this.tech_.scrubbing()) {\n return;\n }\n\n window$1.clearInterval(this.abrTimer_);\n this.abrTimer_ = null;\n }\n /**\n * Get a list of playlists for the currently selected audio playlist\n *\n * @return {Array} the array of audio playlists\n */\n\n\n getAudioTrackPlaylists_() {\n const main = this.main();\n const defaultPlaylists = main && main.playlists || []; // if we don't have any audio groups then we can only\n // assume that the audio tracks are contained in main\n // playlist array, use that or an empty array.\n\n if (!main || !main.mediaGroups || !main.mediaGroups.AUDIO) {\n return defaultPlaylists;\n }\n\n const AUDIO = main.mediaGroups.AUDIO;\n const groupKeys = Object.keys(AUDIO);\n let track; // get the current active track\n\n if (Object.keys(this.mediaTypes_.AUDIO.groups).length) {\n track = this.mediaTypes_.AUDIO.activeTrack(); // or get the default track from main if mediaTypes_ isn't setup yet\n } else {\n // default group is `main` or just the first group.\n const defaultGroup = AUDIO.main || groupKeys.length && AUDIO[groupKeys[0]];\n\n for (const label in defaultGroup) {\n if (defaultGroup[label].default) {\n track = {\n label\n };\n break;\n }\n }\n } // no active track no playlists.\n\n\n if (!track) {\n return defaultPlaylists;\n }\n\n const playlists = []; // get all of the playlists that are possible for the\n // active track.\n\n for (const group in AUDIO) {\n if (AUDIO[group][track.label]) {\n const properties = AUDIO[group][track.label];\n\n if (properties.playlists && properties.playlists.length) {\n playlists.push.apply(playlists, properties.playlists);\n } else if (properties.uri) {\n playlists.push(properties);\n } else if (main.playlists.length) {\n // if an audio group does not have a uri\n // see if we have main playlists that use it as a group.\n // if we do then add those to the playlists list.\n for (let i = 0; i < main.playlists.length; i++) {\n const playlist = main.playlists[i];\n\n if (playlist.attributes && playlist.attributes.AUDIO && playlist.attributes.AUDIO === group) {\n playlists.push(playlist);\n }\n }\n }\n }\n }\n\n if (!playlists.length) {\n return defaultPlaylists;\n }\n\n return playlists;\n }\n /**\n * Register event handlers on the main playlist loader. A helper\n * function for construction time.\n *\n * @private\n */\n\n\n setupMainPlaylistLoaderListeners_() {\n this.mainPlaylistLoader_.on('loadedmetadata', () => {\n const media = this.mainPlaylistLoader_.media();\n const requestTimeout = media.targetDuration * 1.5 * 1000; // If we don't have any more available playlists, we don't want to\n // timeout the request.\n\n if (isLowestEnabledRendition(this.mainPlaylistLoader_.main, this.mainPlaylistLoader_.media())) {\n this.requestOptions_.timeout = 0;\n } else {\n this.requestOptions_.timeout = requestTimeout;\n } // if this isn't a live video and preload permits, start\n // downloading segments\n\n\n if (media.endList && this.tech_.preload() !== 'none') {\n this.mainSegmentLoader_.playlist(media, this.requestOptions_);\n this.mainSegmentLoader_.load();\n }\n\n setupMediaGroups({\n sourceType: this.sourceType_,\n segmentLoaders: {\n AUDIO: this.audioSegmentLoader_,\n SUBTITLES: this.subtitleSegmentLoader_,\n main: this.mainSegmentLoader_\n },\n tech: this.tech_,\n requestOptions: this.requestOptions_,\n mainPlaylistLoader: this.mainPlaylistLoader_,\n vhs: this.vhs_,\n main: this.main(),\n mediaTypes: this.mediaTypes_,\n excludePlaylist: this.excludePlaylist.bind(this)\n });\n this.triggerPresenceUsage_(this.main(), media);\n this.setupFirstPlay();\n\n if (!this.mediaTypes_.AUDIO.activePlaylistLoader || this.mediaTypes_.AUDIO.activePlaylistLoader.media()) {\n this.trigger('selectedinitialmedia');\n } else {\n // We must wait for the active audio playlist loader to\n // finish setting up before triggering this event so the\n // representations API and EME setup is correct\n this.mediaTypes_.AUDIO.activePlaylistLoader.one('loadedmetadata', () => {\n this.trigger('selectedinitialmedia');\n });\n }\n });\n this.mainPlaylistLoader_.on('loadedplaylist', () => {\n if (this.loadOnPlay_) {\n this.tech_.off('play', this.loadOnPlay_);\n }\n\n let updatedPlaylist = this.mainPlaylistLoader_.media();\n\n if (!updatedPlaylist) {\n // Add content steering listeners on first load and init.\n this.attachContentSteeringListeners_();\n this.initContentSteeringController_(); // exclude any variants that are not supported by the browser before selecting\n // an initial media as the playlist selectors do not consider browser support\n\n this.excludeUnsupportedVariants_();\n let selectedMedia;\n\n if (this.enableLowInitialPlaylist) {\n selectedMedia = this.selectInitialPlaylist();\n }\n\n if (!selectedMedia) {\n selectedMedia = this.selectPlaylist();\n }\n\n if (!selectedMedia || !this.shouldSwitchToMedia_(selectedMedia)) {\n return;\n }\n\n this.initialMedia_ = selectedMedia;\n this.switchMedia_(this.initialMedia_, 'initial'); // Under the standard case where a source URL is provided, loadedplaylist will\n // fire again since the playlist will be requested. In the case of vhs-json\n // (where the manifest object is provided as the source), when the media\n // playlist's `segments` list is already available, a media playlist won't be\n // requested, and loadedplaylist won't fire again, so the playlist handler must be\n // called on its own here.\n\n const haveJsonSource = this.sourceType_ === 'vhs-json' && this.initialMedia_.segments;\n\n if (!haveJsonSource) {\n return;\n }\n\n updatedPlaylist = this.initialMedia_;\n }\n\n this.handleUpdatedMediaPlaylist(updatedPlaylist);\n });\n this.mainPlaylistLoader_.on('error', () => {\n const error = this.mainPlaylistLoader_.error;\n this.excludePlaylist({\n playlistToExclude: error.playlist,\n error\n });\n });\n this.mainPlaylistLoader_.on('mediachanging', () => {\n this.mainSegmentLoader_.abort();\n this.mainSegmentLoader_.pause();\n });\n this.mainPlaylistLoader_.on('mediachange', () => {\n const media = this.mainPlaylistLoader_.media();\n const requestTimeout = media.targetDuration * 1.5 * 1000; // If we don't have any more available playlists, we don't want to\n // timeout the request.\n\n if (isLowestEnabledRendition(this.mainPlaylistLoader_.main, this.mainPlaylistLoader_.media())) {\n this.requestOptions_.timeout = 0;\n } else {\n this.requestOptions_.timeout = requestTimeout;\n }\n\n if (this.sourceType_ === 'dash') {\n // we don't want to re-request the same hls playlist right after it was changed\n // Initially it was implemented as workaround to restart playlist loader for live\n // when playlist loader is paused because of playlist exclusions:\n // see: https://github.com/videojs/http-streaming/pull/1339\n // but this introduces duplicate \"loadedplaylist\" event.\n // Ideally we want to re-think playlist loader life-cycle events,\n // but simply checking \"paused\" state should help a lot\n if (this.mainPlaylistLoader_.isPaused) {\n this.mainPlaylistLoader_.load();\n }\n } // TODO: Create a new event on the PlaylistLoader that signals\n // that the segments have changed in some way and use that to\n // update the SegmentLoader instead of doing it twice here and\n // on `loadedplaylist`\n\n\n this.mainSegmentLoader_.pause();\n this.mainSegmentLoader_.playlist(media, this.requestOptions_);\n\n if (this.waitingForFastQualityPlaylistReceived_) {\n this.runFastQualitySwitch_();\n } else {\n this.mainSegmentLoader_.load();\n }\n\n this.tech_.trigger({\n type: 'mediachange',\n bubbles: true\n });\n });\n this.mainPlaylistLoader_.on('playlistunchanged', () => {\n const updatedPlaylist = this.mainPlaylistLoader_.media(); // ignore unchanged playlists that have already been\n // excluded for not-changing. We likely just have a really slowly updating\n // playlist.\n\n if (updatedPlaylist.lastExcludeReason_ === 'playlist-unchanged') {\n return;\n }\n\n const playlistOutdated = this.stuckAtPlaylistEnd_(updatedPlaylist);\n\n if (playlistOutdated) {\n // Playlist has stopped updating and we're stuck at its end. Try to\n // exclude it and switch to another playlist in the hope that that\n // one is updating (and give the player a chance to re-adjust to the\n // safe live point).\n this.excludePlaylist({\n error: {\n message: 'Playlist no longer updating.',\n reason: 'playlist-unchanged'\n }\n }); // useful for monitoring QoS\n\n this.tech_.trigger('playliststuck');\n }\n });\n this.mainPlaylistLoader_.on('renditiondisabled', () => {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-rendition-disabled'\n });\n });\n this.mainPlaylistLoader_.on('renditionenabled', () => {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-rendition-enabled'\n });\n });\n const playlistLoaderEvents = ['manifestrequeststart', 'manifestrequestcomplete', 'manifestparsestart', 'manifestparsecomplete', 'playlistrequeststart', 'playlistrequestcomplete', 'playlistparsestart', 'playlistparsecomplete', 'renditiondisabled', 'renditionenabled'];\n playlistLoaderEvents.forEach(eventName => {\n this.mainPlaylistLoader_.on(eventName, metadata => {\n // trigger directly on the player to ensure early events are fired.\n this.player_.trigger(_extends({}, metadata));\n });\n });\n }\n /**\n * Given an updated media playlist (whether it was loaded for the first time, or\n * refreshed for live playlists), update any relevant properties and state to reflect\n * changes in the media that should be accounted for (e.g., cues and duration).\n *\n * @param {Object} updatedPlaylist the updated media playlist object\n *\n * @private\n */\n\n\n handleUpdatedMediaPlaylist(updatedPlaylist) {\n if (this.useCueTags_) {\n this.updateAdCues_(updatedPlaylist);\n } // TODO: Create a new event on the PlaylistLoader that signals\n // that the segments have changed in some way and use that to\n // update the SegmentLoader instead of doing it twice here and\n // on `mediachange`\n\n\n this.mainSegmentLoader_.pause();\n this.mainSegmentLoader_.playlist(updatedPlaylist, this.requestOptions_);\n\n if (this.waitingForFastQualityPlaylistReceived_) {\n this.runFastQualitySwitch_();\n }\n\n this.updateDuration(!updatedPlaylist.endList); // If the player isn't paused, ensure that the segment loader is running,\n // as it is possible that it was temporarily stopped while waiting for\n // a playlist (e.g., in case the playlist errored and we re-requested it).\n\n if (!this.tech_.paused()) {\n this.mainSegmentLoader_.load();\n\n if (this.audioSegmentLoader_) {\n this.audioSegmentLoader_.load();\n }\n }\n }\n /**\n * A helper function for triggerring presence usage events once per source\n *\n * @private\n */\n\n\n triggerPresenceUsage_(main, media) {\n const mediaGroups = main.mediaGroups || {};\n let defaultDemuxed = true;\n const audioGroupKeys = Object.keys(mediaGroups.AUDIO);\n\n for (const mediaGroup in mediaGroups.AUDIO) {\n for (const label in mediaGroups.AUDIO[mediaGroup]) {\n const properties = mediaGroups.AUDIO[mediaGroup][label];\n\n if (!properties.uri) {\n defaultDemuxed = false;\n }\n }\n }\n\n if (defaultDemuxed) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-demuxed'\n });\n }\n\n if (Object.keys(mediaGroups.SUBTITLES).length) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-webvtt'\n });\n }\n\n if (Vhs$1.Playlist.isAes(media)) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-aes'\n });\n }\n\n if (audioGroupKeys.length && Object.keys(mediaGroups.AUDIO[audioGroupKeys[0]]).length > 1) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-alternate-audio'\n });\n }\n\n if (this.useCueTags_) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-playlist-cue-tags'\n });\n }\n }\n\n shouldSwitchToMedia_(nextPlaylist) {\n const currentPlaylist = this.mainPlaylistLoader_.media() || this.mainPlaylistLoader_.pendingMedia_;\n const currentTime = this.tech_.currentTime();\n const bufferLowWaterLine = this.bufferLowWaterLine();\n const bufferHighWaterLine = this.bufferHighWaterLine();\n const buffered = this.tech_.buffered();\n return shouldSwitchToMedia({\n buffered,\n currentTime,\n currentPlaylist,\n nextPlaylist,\n bufferLowWaterLine,\n bufferHighWaterLine,\n duration: this.duration(),\n bufferBasedABR: this.bufferBasedABR,\n log: this.logger_\n });\n }\n /**\n * Register event handlers on the segment loaders. A helper function\n * for construction time.\n *\n * @private\n */\n\n\n setupSegmentLoaderListeners_() {\n this.mainSegmentLoader_.on('bandwidthupdate', () => {\n // Whether or not buffer based ABR or another ABR is used, on a bandwidth change it's\n // useful to check to see if a rendition switch should be made.\n this.checkABR_('bandwidthupdate');\n this.tech_.trigger('bandwidthupdate');\n });\n this.mainSegmentLoader_.on('timeout', () => {\n if (this.bufferBasedABR) {\n // If a rendition change is needed, then it would've be done on `bandwidthupdate`.\n // Here the only consideration is that for buffer based ABR there's no guarantee\n // of an immediate switch (since the bandwidth is averaged with a timeout\n // bandwidth value of 1), so force a load on the segment loader to keep it going.\n this.mainSegmentLoader_.load();\n }\n }); // `progress` events are not reliable enough of a bandwidth measure to trigger buffer\n // based ABR.\n\n if (!this.bufferBasedABR) {\n this.mainSegmentLoader_.on('progress', () => {\n this.trigger('progress');\n });\n }\n\n this.mainSegmentLoader_.on('error', () => {\n const error = this.mainSegmentLoader_.error();\n this.excludePlaylist({\n playlistToExclude: error.playlist,\n error\n });\n });\n this.mainSegmentLoader_.on('appenderror', () => {\n this.error = this.mainSegmentLoader_.error_;\n this.trigger('error');\n });\n this.mainSegmentLoader_.on('syncinfoupdate', () => {\n this.onSyncInfoUpdate_();\n });\n this.mainSegmentLoader_.on('timestampoffset', () => {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-timestamp-offset'\n });\n });\n this.audioSegmentLoader_.on('syncinfoupdate', () => {\n this.onSyncInfoUpdate_();\n });\n this.audioSegmentLoader_.on('appenderror', () => {\n this.error = this.audioSegmentLoader_.error_;\n this.trigger('error');\n });\n this.mainSegmentLoader_.on('ended', () => {\n this.logger_('main segment loader ended');\n this.onEndOfStream();\n }); // There is the possibility of the video segment and the audio segment\n // at a current time to be on different timelines. When this occurs, the player\n // forwards playback to a point where these two segment types are back on the same\n // timeline. This time will be just after the end of the audio segment that is on\n // a previous timeline.\n\n this.timelineChangeController_.on('audioTimelineBehind', () => {\n const segmentInfo = this.audioSegmentLoader_.pendingSegment_;\n\n if (!segmentInfo || !segmentInfo.segment || !segmentInfo.segment.syncInfo) {\n return;\n } // Update the current time to just after the faulty audio segment.\n // This moves playback to a spot where both audio and video segments\n // are on the same timeline.\n\n\n const newTime = segmentInfo.segment.syncInfo.end + 0.01;\n this.tech_.setCurrentTime(newTime);\n });\n this.timelineChangeController_.on('fixBadTimelineChange', () => {\n // pause, reset-everything and load for all segment-loaders\n this.logger_('Fix bad timeline change. Restarting al segment loaders...');\n this.mainSegmentLoader_.pause();\n this.mainSegmentLoader_.resetEverything();\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n this.audioSegmentLoader_.pause();\n this.audioSegmentLoader_.resetEverything();\n }\n\n if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {\n this.subtitleSegmentLoader_.pause();\n this.subtitleSegmentLoader_.resetEverything();\n } // start segment loader loading in case they are paused\n\n\n this.load();\n });\n this.mainSegmentLoader_.on('earlyabort', event => {\n // never try to early abort with the new ABR algorithm\n if (this.bufferBasedABR) {\n return;\n }\n\n this.delegateLoaders_('all', ['abort']);\n this.excludePlaylist({\n error: {\n message: 'Aborted early because there isn\\'t enough bandwidth to complete ' + 'the request without rebuffering.'\n },\n playlistExclusionDuration: ABORT_EARLY_EXCLUSION_SECONDS\n });\n });\n\n const updateCodecs = () => {\n if (!this.sourceUpdater_.hasCreatedSourceBuffers()) {\n return this.tryToCreateSourceBuffers_();\n }\n\n const codecs = this.getCodecsOrExclude_(); // no codecs means that the playlist was excluded\n\n if (!codecs) {\n return;\n }\n\n this.sourceUpdater_.addOrChangeSourceBuffers(codecs);\n };\n\n this.mainSegmentLoader_.on('trackinfo', updateCodecs);\n this.audioSegmentLoader_.on('trackinfo', updateCodecs);\n this.mainSegmentLoader_.on('fmp4', () => {\n if (!this.triggeredFmp4Usage) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-fmp4'\n });\n this.triggeredFmp4Usage = true;\n }\n });\n this.audioSegmentLoader_.on('fmp4', () => {\n if (!this.triggeredFmp4Usage) {\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-fmp4'\n });\n this.triggeredFmp4Usage = true;\n }\n });\n this.audioSegmentLoader_.on('ended', () => {\n this.logger_('audioSegmentLoader ended');\n this.onEndOfStream();\n });\n const segmentLoaderEvents = ['segmentselected', 'segmentloadstart', 'segmentloaded', 'segmentkeyloadstart', 'segmentkeyloadcomplete', 'segmentdecryptionstart', 'segmentdecryptioncomplete', 'segmenttransmuxingstart', 'segmenttransmuxingcomplete', 'segmenttransmuxingtrackinfoavailable', 'segmenttransmuxingtiminginfoavailable', 'segmentappendstart', 'appendsdone', 'bandwidthupdated', 'timelinechange', 'codecschange'];\n segmentLoaderEvents.forEach(eventName => {\n this.mainSegmentLoader_.on(eventName, metadata => {\n this.player_.trigger(_extends({}, metadata));\n });\n this.audioSegmentLoader_.on(eventName, metadata => {\n this.player_.trigger(_extends({}, metadata));\n });\n this.subtitleSegmentLoader_.on(eventName, metadata => {\n this.player_.trigger(_extends({}, metadata));\n });\n });\n }\n\n mediaSecondsLoaded_() {\n return Math.max(this.audioSegmentLoader_.mediaSecondsLoaded + this.mainSegmentLoader_.mediaSecondsLoaded);\n }\n /**\n * Call load on our SegmentLoaders\n */\n\n\n load() {\n this.mainSegmentLoader_.load();\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n this.audioSegmentLoader_.load();\n }\n\n if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {\n this.subtitleSegmentLoader_.load();\n }\n }\n /**\n * Call pause on our SegmentLoaders\n */\n\n\n pause() {\n this.mainSegmentLoader_.pause();\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n this.audioSegmentLoader_.pause();\n }\n\n if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {\n this.subtitleSegmentLoader_.pause();\n }\n }\n /**\n * Re-tune playback quality level for the current player\n * conditions. This method will perform destructive actions like removing\n * already buffered content in order to readjust the currently active\n * playlist quickly. This is good for manual quality changes\n *\n * @private\n */\n\n\n fastQualityChange_(media = this.selectPlaylist()) {\n if (media && media === this.mainPlaylistLoader_.media()) {\n this.logger_('skipping fastQualityChange because new media is same as old');\n return;\n }\n\n this.switchMedia_(media, 'fast-quality'); // we would like to avoid race condition when we call fastQuality,\n // reset everything and start loading segments from prev segments instead of new because new playlist is not received yet\n\n this.waitingForFastQualityPlaylistReceived_ = true;\n }\n\n runFastQualitySwitch_() {\n this.waitingForFastQualityPlaylistReceived_ = false;\n this.mainSegmentLoader_.pause();\n this.mainSegmentLoader_.resetEverything();\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n this.audioSegmentLoader_.pause();\n this.audioSegmentLoader_.resetEverything();\n }\n\n if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {\n this.subtitleSegmentLoader_.pause();\n this.subtitleSegmentLoader_.resetEverything();\n } // start segment loader loading in case they are paused\n\n\n this.load();\n }\n /**\n * Begin playback.\n */\n\n\n play() {\n if (this.setupFirstPlay()) {\n return;\n }\n\n if (this.tech_.ended()) {\n this.tech_.setCurrentTime(0);\n }\n\n if (this.hasPlayed_) {\n this.load();\n }\n\n const seekable = this.tech_.seekable(); // if the viewer has paused and we fell out of the live window,\n // seek forward to the live point\n\n if (this.tech_.duration() === Infinity) {\n if (this.tech_.currentTime() < seekable.start(0)) {\n return this.tech_.setCurrentTime(seekable.end(seekable.length - 1));\n }\n }\n }\n /**\n * Seek to the latest media position if this is a live video and the\n * player and video are loaded and initialized.\n */\n\n\n setupFirstPlay() {\n const media = this.mainPlaylistLoader_.media(); // Check that everything is ready to begin buffering for the first call to play\n // If 1) there is no active media\n // 2) the player is paused\n // 3) the first play has already been setup\n // then exit early\n\n if (!media || this.tech_.paused() || this.hasPlayed_) {\n return false;\n } // when the video is a live stream and/or has a start time\n\n\n if (!media.endList || media.start) {\n const seekable = this.seekable();\n\n if (!seekable.length) {\n // without a seekable range, the player cannot seek to begin buffering at the\n // live or start point\n return false;\n }\n\n const seekableEnd = seekable.end(0);\n let startPoint = seekableEnd;\n\n if (media.start) {\n const offset = media.start.timeOffset;\n\n if (offset < 0) {\n startPoint = Math.max(seekableEnd + offset, seekable.start(0));\n } else {\n startPoint = Math.min(seekableEnd, offset);\n }\n } // trigger firstplay to inform the source handler to ignore the next seek event\n\n\n this.trigger('firstplay'); // seek to the live point\n\n this.tech_.setCurrentTime(startPoint);\n }\n\n this.hasPlayed_ = true; // we can begin loading now that everything is ready\n\n this.load();\n return true;\n }\n /**\n * handle the sourceopen event on the MediaSource\n *\n * @private\n */\n\n\n handleSourceOpen_() {\n // Only attempt to create the source buffer if none already exist.\n // handleSourceOpen is also called when we are \"re-opening\" a source buffer\n // after `endOfStream` has been called (in response to a seek for instance)\n this.tryToCreateSourceBuffers_(); // if autoplay is enabled, begin playback. This is duplicative of\n // code in video.js but is required because play() must be invoked\n // *after* the media source has opened.\n\n if (this.tech_.autoplay()) {\n const playPromise = this.tech_.play(); // Catch/silence error when a pause interrupts a play request\n // on browsers which return a promise\n\n if (typeof playPromise !== 'undefined' && typeof playPromise.then === 'function') {\n playPromise.then(null, e => {});\n }\n }\n\n this.trigger('sourceopen');\n }\n /**\n * handle the sourceended event on the MediaSource\n *\n * @private\n */\n\n\n handleSourceEnded_() {\n if (!this.inbandTextTracks_.metadataTrack_) {\n return;\n }\n\n const cues = this.inbandTextTracks_.metadataTrack_.cues;\n\n if (!cues || !cues.length) {\n return;\n }\n\n const duration = this.duration();\n cues[cues.length - 1].endTime = isNaN(duration) || Math.abs(duration) === Infinity ? Number.MAX_VALUE : duration;\n }\n /**\n * handle the durationchange event on the MediaSource\n *\n * @private\n */\n\n\n handleDurationChange_() {\n this.tech_.trigger('durationchange');\n }\n /**\n * Calls endOfStream on the media source when all active stream types have called\n * endOfStream\n *\n * @param {string} streamType\n * Stream type of the segment loader that called endOfStream\n * @private\n */\n\n\n onEndOfStream() {\n let isEndOfStream = this.mainSegmentLoader_.ended_;\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n const mainMediaInfo = this.mainSegmentLoader_.getCurrentMediaInfo_(); // if the audio playlist loader exists, then alternate audio is active\n\n if (!mainMediaInfo || mainMediaInfo.hasVideo) {\n // if we do not know if the main segment loader contains video yet or if we\n // definitively know the main segment loader contains video, then we need to wait\n // for both main and audio segment loaders to call endOfStream\n isEndOfStream = isEndOfStream && this.audioSegmentLoader_.ended_;\n } else {\n // otherwise just rely on the audio loader\n isEndOfStream = this.audioSegmentLoader_.ended_;\n }\n }\n\n if (!isEndOfStream) {\n return;\n }\n\n this.stopABRTimer_();\n this.sourceUpdater_.endOfStream();\n }\n /**\n * Check if a playlist has stopped being updated\n *\n * @param {Object} playlist the media playlist object\n * @return {boolean} whether the playlist has stopped being updated or not\n */\n\n\n stuckAtPlaylistEnd_(playlist) {\n const seekable = this.seekable();\n\n if (!seekable.length) {\n // playlist doesn't have enough information to determine whether we are stuck\n return false;\n }\n\n const expired = this.syncController_.getExpiredTime(playlist, this.duration());\n\n if (expired === null) {\n return false;\n } // does not use the safe live end to calculate playlist end, since we\n // don't want to say we are stuck while there is still content\n\n\n const absolutePlaylistEnd = Vhs$1.Playlist.playlistEnd(playlist, expired);\n const currentTime = this.tech_.currentTime();\n const buffered = this.tech_.buffered();\n\n if (!buffered.length) {\n // return true if the playhead reached the absolute end of the playlist\n return absolutePlaylistEnd - currentTime <= SAFE_TIME_DELTA;\n }\n\n const bufferedEnd = buffered.end(buffered.length - 1); // return true if there is too little buffer left and buffer has reached absolute\n // end of playlist\n\n return bufferedEnd - currentTime <= SAFE_TIME_DELTA && absolutePlaylistEnd - bufferedEnd <= SAFE_TIME_DELTA;\n }\n /**\n * Exclude a playlist for a set amount of time, making it unavailable for selection by\n * the rendition selection algorithm, then force a new playlist (rendition) selection.\n *\n * @param {Object=} playlistToExclude\n * the playlist to exclude, defaults to the currently selected playlist\n * @param {Object=} error\n * an optional error\n * @param {number=} playlistExclusionDuration\n * an optional number of seconds to exclude the playlist\n */\n\n\n excludePlaylist({\n playlistToExclude = this.mainPlaylistLoader_.media(),\n error = {},\n playlistExclusionDuration\n }) {\n // If the `error` was generated by the playlist loader, it will contain\n // the playlist we were trying to load (but failed) and that should be\n // excluded instead of the currently selected playlist which is likely\n // out-of-date in this scenario\n playlistToExclude = playlistToExclude || this.mainPlaylistLoader_.media();\n playlistExclusionDuration = playlistExclusionDuration || error.playlistExclusionDuration || this.playlistExclusionDuration; // If there is no current playlist, then an error occurred while we were\n // trying to load the main OR while we were disposing of the tech\n\n if (!playlistToExclude) {\n this.error = error;\n\n if (this.mediaSource.readyState !== 'open') {\n this.trigger('error');\n } else {\n this.sourceUpdater_.endOfStream('network');\n }\n\n return;\n }\n\n playlistToExclude.playlistErrors_++;\n const playlists = this.mainPlaylistLoader_.main.playlists;\n const enabledPlaylists = playlists.filter(isEnabled);\n const isFinalRendition = enabledPlaylists.length === 1 && enabledPlaylists[0] === playlistToExclude; // Don't exclude the only playlist unless it was excluded\n // forever\n\n if (playlists.length === 1 && playlistExclusionDuration !== Infinity) {\n videojs.log.warn(`Problem encountered with playlist ${playlistToExclude.id}. ` + 'Trying again since it is the only playlist.');\n this.tech_.trigger('retryplaylist'); // if this is a final rendition, we should delay\n\n return this.mainPlaylistLoader_.load(isFinalRendition);\n }\n\n if (isFinalRendition) {\n // If we're content steering, try other pathways.\n if (this.main().contentSteering) {\n const pathway = this.pathwayAttribute_(playlistToExclude); // Ignore at least 1 steering manifest refresh.\n\n const reIncludeDelay = this.contentSteeringController_.steeringManifest.ttl * 1000;\n this.contentSteeringController_.excludePathway(pathway);\n this.excludeThenChangePathway_();\n setTimeout(() => {\n this.contentSteeringController_.addAvailablePathway(pathway);\n }, reIncludeDelay);\n return;\n } // Since we're on the final non-excluded playlist, and we're about to exclude\n // it, instead of erring the player or retrying this playlist, clear out the current\n // exclusion list. This allows other playlists to be attempted in case any have been\n // fixed.\n\n\n let reincluded = false;\n playlists.forEach(playlist => {\n // skip current playlist which is about to be excluded\n if (playlist === playlistToExclude) {\n return;\n }\n\n const excludeUntil = playlist.excludeUntil; // a playlist cannot be reincluded if it wasn't excluded to begin with.\n\n if (typeof excludeUntil !== 'undefined' && excludeUntil !== Infinity) {\n reincluded = true;\n delete playlist.excludeUntil;\n }\n });\n\n if (reincluded) {\n videojs.log.warn('Removing other playlists from the exclusion list because the last ' + 'rendition is about to be excluded.'); // Technically we are retrying a playlist, in that we are simply retrying a previous\n // playlist. This is needed for users relying on the retryplaylist event to catch a\n // case where the player might be stuck and looping through \"dead\" playlists.\n\n this.tech_.trigger('retryplaylist');\n }\n } // Exclude this playlist\n\n\n let excludeUntil;\n\n if (playlistToExclude.playlistErrors_ > this.maxPlaylistRetries) {\n excludeUntil = Infinity;\n } else {\n excludeUntil = Date.now() + playlistExclusionDuration * 1000;\n }\n\n playlistToExclude.excludeUntil = excludeUntil;\n\n if (error.reason) {\n playlistToExclude.lastExcludeReason_ = error.reason;\n }\n\n this.tech_.trigger('excludeplaylist');\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-rendition-excluded'\n }); // TODO: only load a new playlist if we're excluding the current playlist\n // If this function was called with a playlist that's not the current active playlist\n // (e.g., media().id !== playlistToExclude.id),\n // then a new playlist should not be selected and loaded, as there's nothing wrong with the current playlist.\n\n const nextPlaylist = this.selectPlaylist();\n\n if (!nextPlaylist) {\n this.error = 'Playback cannot continue. No available working or supported playlists.';\n this.trigger('error');\n return;\n }\n\n const logFn = error.internal ? this.logger_ : videojs.log.warn;\n const errorMessage = error.message ? ' ' + error.message : '';\n logFn(`${error.internal ? 'Internal problem' : 'Problem'} encountered with playlist ${playlistToExclude.id}.` + `${errorMessage} Switching to playlist ${nextPlaylist.id}.`); // if audio group changed reset audio loaders\n\n if (nextPlaylist.attributes.AUDIO !== playlistToExclude.attributes.AUDIO) {\n this.delegateLoaders_('audio', ['abort', 'pause']);\n } // if subtitle group changed reset subtitle loaders\n\n\n if (nextPlaylist.attributes.SUBTITLES !== playlistToExclude.attributes.SUBTITLES) {\n this.delegateLoaders_('subtitle', ['abort', 'pause']);\n }\n\n this.delegateLoaders_('main', ['abort', 'pause']);\n const delayDuration = nextPlaylist.targetDuration / 2 * 1000 || 5 * 1000;\n const shouldDelay = typeof nextPlaylist.lastRequest === 'number' && Date.now() - nextPlaylist.lastRequest <= delayDuration; // delay if it's a final rendition or if the last refresh is sooner than half targetDuration\n\n return this.switchMedia_(nextPlaylist, 'exclude', isFinalRendition || shouldDelay);\n }\n /**\n * Pause all segment/playlist loaders\n */\n\n\n pauseLoading() {\n this.delegateLoaders_('all', ['abort', 'pause']);\n this.stopABRTimer_();\n }\n /**\n * Call a set of functions in order on playlist loaders, segment loaders,\n * or both types of loaders.\n *\n * @param {string} filter\n * Filter loaders that should call fnNames using a string. Can be:\n * * all - run on all loaders\n * * audio - run on all audio loaders\n * * subtitle - run on all subtitle loaders\n * * main - run on the main loaders\n *\n * @param {Array|string} fnNames\n * A string or array of function names to call.\n */\n\n\n delegateLoaders_(filter, fnNames) {\n const loaders = [];\n const dontFilterPlaylist = filter === 'all';\n\n if (dontFilterPlaylist || filter === 'main') {\n loaders.push(this.mainPlaylistLoader_);\n }\n\n const mediaTypes = [];\n\n if (dontFilterPlaylist || filter === 'audio') {\n mediaTypes.push('AUDIO');\n }\n\n if (dontFilterPlaylist || filter === 'subtitle') {\n mediaTypes.push('CLOSED-CAPTIONS');\n mediaTypes.push('SUBTITLES');\n }\n\n mediaTypes.forEach(mediaType => {\n const loader = this.mediaTypes_[mediaType] && this.mediaTypes_[mediaType].activePlaylistLoader;\n\n if (loader) {\n loaders.push(loader);\n }\n });\n ['main', 'audio', 'subtitle'].forEach(name => {\n const loader = this[`${name}SegmentLoader_`];\n\n if (loader && (filter === name || filter === 'all')) {\n loaders.push(loader);\n }\n });\n loaders.forEach(loader => fnNames.forEach(fnName => {\n if (typeof loader[fnName] === 'function') {\n loader[fnName]();\n }\n }));\n }\n /**\n * set the current time on all segment loaders\n *\n * @param {TimeRange} currentTime the current time to set\n * @return {TimeRange} the current time\n */\n\n\n setCurrentTime(currentTime) {\n const buffered = findRange(this.tech_.buffered(), currentTime);\n\n if (!(this.mainPlaylistLoader_ && this.mainPlaylistLoader_.media())) {\n // return immediately if the metadata is not ready yet\n return 0;\n } // it's clearly an edge-case but don't thrown an error if asked to\n // seek within an empty playlist\n\n\n if (!this.mainPlaylistLoader_.media().segments) {\n return 0;\n } // if the seek location is already buffered, continue buffering as usual\n\n\n if (buffered && buffered.length) {\n return currentTime;\n } // cancel outstanding requests so we begin buffering at the new\n // location\n\n\n this.mainSegmentLoader_.pause();\n this.mainSegmentLoader_.resetEverything();\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n this.audioSegmentLoader_.pause();\n this.audioSegmentLoader_.resetEverything();\n }\n\n if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {\n this.subtitleSegmentLoader_.pause();\n this.subtitleSegmentLoader_.resetEverything();\n } // start segment loader loading in case they are paused\n\n\n this.load();\n }\n /**\n * get the current duration\n *\n * @return {TimeRange} the duration\n */\n\n\n duration() {\n if (!this.mainPlaylistLoader_) {\n return 0;\n }\n\n const media = this.mainPlaylistLoader_.media();\n\n if (!media) {\n // no playlists loaded yet, so can't determine a duration\n return 0;\n } // Don't rely on the media source for duration in the case of a live playlist since\n // setting the native MediaSource's duration to infinity ends up with consequences to\n // seekable behavior. See https://github.com/w3c/media-source/issues/5 for details.\n //\n // This is resolved in the spec by https://github.com/w3c/media-source/pull/92,\n // however, few browsers have support for setLiveSeekableRange()\n // https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/setLiveSeekableRange\n //\n // Until a time when the duration of the media source can be set to infinity, and a\n // seekable range specified across browsers, just return Infinity.\n\n\n if (!media.endList) {\n return Infinity;\n } // Since this is a VOD video, it is safe to rely on the media source's duration (if\n // available). If it's not available, fall back to a playlist-calculated estimate.\n\n\n if (this.mediaSource) {\n return this.mediaSource.duration;\n }\n\n return Vhs$1.Playlist.duration(media);\n }\n /**\n * check the seekable range\n *\n * @return {TimeRange} the seekable range\n */\n\n\n seekable() {\n return this.seekable_;\n }\n\n getSeekableRange_(playlistLoader, mediaType) {\n const media = playlistLoader.media();\n\n if (!media) {\n return null;\n }\n\n const mediaSequenceSync = this.syncController_.getMediaSequenceSync(mediaType);\n\n if (mediaSequenceSync && mediaSequenceSync.isReliable) {\n const start = mediaSequenceSync.start;\n const end = mediaSequenceSync.end;\n\n if (!isFinite(start) || !isFinite(end)) {\n return null;\n }\n\n const liveEdgeDelay = Vhs$1.Playlist.liveEdgeDelay(this.mainPlaylistLoader_.main, media); // Make sure our seekable end is not negative\n\n const calculatedEnd = Math.max(0, end - liveEdgeDelay);\n\n if (calculatedEnd < start) {\n return null;\n }\n\n return createTimeRanges([[start, calculatedEnd]]);\n }\n\n const expired = this.syncController_.getExpiredTime(media, this.duration());\n\n if (expired === null) {\n return null;\n }\n\n const seekable = Vhs$1.Playlist.seekable(media, expired, Vhs$1.Playlist.liveEdgeDelay(this.mainPlaylistLoader_.main, media));\n return seekable.length ? seekable : null;\n }\n\n computeFinalSeekable_(mainSeekable, audioSeekable) {\n if (!audioSeekable) {\n return mainSeekable;\n }\n\n const mainStart = mainSeekable.start(0);\n const mainEnd = mainSeekable.end(0);\n const audioStart = audioSeekable.start(0);\n const audioEnd = audioSeekable.end(0);\n\n if (audioStart > mainEnd || mainStart > audioEnd) {\n // Seekables are far apart, rely on main\n return mainSeekable;\n } // Return the overlapping seekable range\n\n\n return createTimeRanges([[Math.max(mainStart, audioStart), Math.min(mainEnd, audioEnd)]]);\n }\n\n onSyncInfoUpdate_() {\n // TODO check for creation of both source buffers before updating seekable\n //\n // A fix was made to this function where a check for\n // this.sourceUpdater_.hasCreatedSourceBuffers\n // was added to ensure that both source buffers were created before seekable was\n // updated. However, it originally had a bug where it was checking for a true and\n // returning early instead of checking for false. Setting it to check for false to\n // return early though created other issues. A call to play() would check for seekable\n // end without verifying that a seekable range was present. In addition, even checking\n // for that didn't solve some issues, as handleFirstPlay is sometimes worked around\n // due to a media update calling load on the segment loaders, skipping a seek to live,\n // thereby starting live streams at the beginning of the stream rather than at the end.\n //\n // This conditional should be fixed to wait for the creation of two source buffers at\n // the same time as the other sections of code are fixed to properly seek to live and\n // not throw an error due to checking for a seekable end when no seekable range exists.\n //\n // For now, fall back to the older behavior, with the understanding that the seekable\n // range may not be completely correct, leading to a suboptimal initial live point.\n if (!this.mainPlaylistLoader_) {\n return;\n }\n\n const mainSeekable = this.getSeekableRange_(this.mainPlaylistLoader_, 'main');\n\n if (!mainSeekable) {\n return;\n }\n\n let audioSeekable;\n\n if (this.mediaTypes_.AUDIO.activePlaylistLoader) {\n audioSeekable = this.getSeekableRange_(this.mediaTypes_.AUDIO.activePlaylistLoader, 'audio');\n\n if (!audioSeekable) {\n return;\n }\n }\n\n const oldSeekable = this.seekable_;\n this.seekable_ = this.computeFinalSeekable_(mainSeekable, audioSeekable);\n\n if (!this.seekable_) {\n return;\n }\n\n if (oldSeekable && oldSeekable.length && this.seekable_.length) {\n if (oldSeekable.start(0) === this.seekable_.start(0) && oldSeekable.end(0) === this.seekable_.end(0)) {\n // Seekable range hasn't changed\n return;\n }\n }\n\n this.logger_(`seekable updated [${printableRange(this.seekable_)}]`);\n const metadata = {\n seekableRanges: this.seekable_\n };\n this.trigger({\n type: 'seekablerangeschanged',\n metadata\n });\n this.tech_.trigger('seekablechanged');\n }\n /**\n * Update the player duration\n */\n\n\n updateDuration(isLive) {\n if (this.updateDuration_) {\n this.mediaSource.removeEventListener('sourceopen', this.updateDuration_);\n this.updateDuration_ = null;\n }\n\n if (this.mediaSource.readyState !== 'open') {\n this.updateDuration_ = this.updateDuration.bind(this, isLive);\n this.mediaSource.addEventListener('sourceopen', this.updateDuration_);\n return;\n }\n\n if (isLive) {\n const seekable = this.seekable();\n\n if (!seekable.length) {\n return;\n } // Even in the case of a live playlist, the native MediaSource's duration should not\n // be set to Infinity (even though this would be expected for a live playlist), since\n // setting the native MediaSource's duration to infinity ends up with consequences to\n // seekable behavior. See https://github.com/w3c/media-source/issues/5 for details.\n //\n // This is resolved in the spec by https://github.com/w3c/media-source/pull/92,\n // however, few browsers have support for setLiveSeekableRange()\n // https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/setLiveSeekableRange\n //\n // Until a time when the duration of the media source can be set to infinity, and a\n // seekable range specified across browsers, the duration should be greater than or\n // equal to the last possible seekable value.\n // MediaSource duration starts as NaN\n // It is possible (and probable) that this case will never be reached for many\n // sources, since the MediaSource reports duration as the highest value without\n // accounting for timestamp offset. For example, if the timestamp offset is -100 and\n // we buffered times 0 to 100 with real times of 100 to 200, even though current\n // time will be between 0 and 100, the native media source may report the duration\n // as 200. However, since we report duration separate from the media source (as\n // Infinity), and as long as the native media source duration value is greater than\n // our reported seekable range, seeks will work as expected. The large number as\n // duration for live is actually a strategy used by some players to work around the\n // issue of live seekable ranges cited above.\n\n\n if (isNaN(this.mediaSource.duration) || this.mediaSource.duration < seekable.end(seekable.length - 1)) {\n this.sourceUpdater_.setDuration(seekable.end(seekable.length - 1));\n }\n\n return;\n }\n\n const buffered = this.tech_.buffered();\n let duration = Vhs$1.Playlist.duration(this.mainPlaylistLoader_.media());\n\n if (buffered.length > 0) {\n duration = Math.max(duration, buffered.end(buffered.length - 1));\n }\n\n if (this.mediaSource.duration !== duration) {\n this.sourceUpdater_.setDuration(duration);\n }\n }\n /**\n * dispose of the PlaylistController and everything\n * that it controls\n */\n\n\n dispose() {\n this.trigger('dispose');\n this.decrypter_.terminate();\n this.mainPlaylistLoader_.dispose();\n this.mainSegmentLoader_.dispose();\n this.contentSteeringController_.dispose();\n this.keyStatusMap_.clear();\n\n if (this.loadOnPlay_) {\n this.tech_.off('play', this.loadOnPlay_);\n }\n\n ['AUDIO', 'SUBTITLES'].forEach(type => {\n const groups = this.mediaTypes_[type].groups;\n\n for (const id in groups) {\n groups[id].forEach(group => {\n if (group.playlistLoader) {\n group.playlistLoader.dispose();\n }\n });\n }\n });\n this.audioSegmentLoader_.dispose();\n this.subtitleSegmentLoader_.dispose();\n this.sourceUpdater_.dispose();\n this.timelineChangeController_.dispose();\n this.stopABRTimer_();\n\n if (this.updateDuration_) {\n this.mediaSource.removeEventListener('sourceopen', this.updateDuration_);\n }\n\n this.mediaSource.removeEventListener('durationchange', this.handleDurationChange_); // load the media source into the player\n\n this.mediaSource.removeEventListener('sourceopen', this.handleSourceOpen_);\n this.mediaSource.removeEventListener('sourceended', this.handleSourceEnded_);\n this.off();\n }\n /**\n * return the main playlist object if we have one\n *\n * @return {Object} the main playlist object that we parsed\n */\n\n\n main() {\n return this.mainPlaylistLoader_.main;\n }\n /**\n * return the currently selected playlist\n *\n * @return {Object} the currently selected playlist object that we parsed\n */\n\n\n media() {\n // playlist loader will not return media if it has not been fully loaded\n return this.mainPlaylistLoader_.media() || this.initialMedia_;\n }\n\n areMediaTypesKnown_() {\n const usingAudioLoader = !!this.mediaTypes_.AUDIO.activePlaylistLoader;\n const hasMainMediaInfo = !!this.mainSegmentLoader_.getCurrentMediaInfo_(); // if we are not using an audio loader, then we have audio media info\n // otherwise check on the segment loader.\n\n const hasAudioMediaInfo = !usingAudioLoader ? true : !!this.audioSegmentLoader_.getCurrentMediaInfo_(); // one or both loaders has not loaded sufficently to get codecs\n\n if (!hasMainMediaInfo || !hasAudioMediaInfo) {\n return false;\n }\n\n return true;\n } // find from and to for codec switch event\n\n\n getCodecsOrExclude_() {\n const media = {\n main: this.mainSegmentLoader_.getCurrentMediaInfo_() || {},\n audio: this.audioSegmentLoader_.getCurrentMediaInfo_() || {}\n };\n const playlist = this.mainSegmentLoader_.getPendingSegmentPlaylist() || this.media(); // set \"main\" media equal to video\n\n media.video = media.main;\n const playlistCodecs = codecsForPlaylist(this.main(), playlist);\n const codecs = {};\n const usingAudioLoader = !!this.mediaTypes_.AUDIO.activePlaylistLoader;\n\n if (media.main.hasVideo) {\n codecs.video = playlistCodecs.video || media.main.videoCodec || DEFAULT_VIDEO_CODEC;\n }\n\n if (media.main.isMuxed) {\n codecs.video += `,${playlistCodecs.audio || media.main.audioCodec || DEFAULT_AUDIO_CODEC}`;\n }\n\n if (media.main.hasAudio && !media.main.isMuxed || media.audio.hasAudio || usingAudioLoader) {\n codecs.audio = playlistCodecs.audio || media.main.audioCodec || media.audio.audioCodec || DEFAULT_AUDIO_CODEC; // set audio isFmp4 so we use the correct \"supports\" function below\n\n media.audio.isFmp4 = media.main.hasAudio && !media.main.isMuxed ? media.main.isFmp4 : media.audio.isFmp4;\n } // no codecs, no playback.\n\n\n if (!codecs.audio && !codecs.video) {\n this.excludePlaylist({\n playlistToExclude: playlist,\n error: {\n message: 'Could not determine codecs for playlist.'\n },\n playlistExclusionDuration: Infinity\n });\n return;\n } // fmp4 relies on browser support, while ts relies on muxer support\n\n\n const supportFunction = (isFmp4, codec) => isFmp4 ? browserSupportsCodec(codec, this.usingManagedMediaSource_) : muxerSupportsCodec(codec);\n\n const unsupportedCodecs = {};\n let unsupportedAudio;\n ['video', 'audio'].forEach(function (type) {\n if (codecs.hasOwnProperty(type) && !supportFunction(media[type].isFmp4, codecs[type])) {\n const supporter = media[type].isFmp4 ? 'browser' : 'muxer';\n unsupportedCodecs[supporter] = unsupportedCodecs[supporter] || [];\n unsupportedCodecs[supporter].push(codecs[type]);\n\n if (type === 'audio') {\n unsupportedAudio = supporter;\n }\n }\n });\n\n if (usingAudioLoader && unsupportedAudio && playlist.attributes.AUDIO) {\n const audioGroup = playlist.attributes.AUDIO;\n this.main().playlists.forEach(variant => {\n const variantAudioGroup = variant.attributes && variant.attributes.AUDIO;\n\n if (variantAudioGroup === audioGroup && variant !== playlist) {\n variant.excludeUntil = Infinity;\n }\n });\n this.logger_(`excluding audio group ${audioGroup} as ${unsupportedAudio} does not support codec(s): \"${codecs.audio}\"`);\n } // if we have any unsupported codecs exclude this playlist.\n\n\n if (Object.keys(unsupportedCodecs).length) {\n const message = Object.keys(unsupportedCodecs).reduce((acc, supporter) => {\n if (acc) {\n acc += ', ';\n }\n\n acc += `${supporter} does not support codec(s): \"${unsupportedCodecs[supporter].join(',')}\"`;\n return acc;\n }, '') + '.';\n this.excludePlaylist({\n playlistToExclude: playlist,\n error: {\n internal: true,\n message\n },\n playlistExclusionDuration: Infinity\n });\n return;\n } // check if codec switching is happening\n\n\n if (this.sourceUpdater_.hasCreatedSourceBuffers() && !this.sourceUpdater_.canChangeType()) {\n const switchMessages = [];\n ['video', 'audio'].forEach(type => {\n const newCodec = (parseCodecs(this.sourceUpdater_.codecs[type] || '')[0] || {}).type;\n const oldCodec = (parseCodecs(codecs[type] || '')[0] || {}).type;\n\n if (newCodec && oldCodec && newCodec.toLowerCase() !== oldCodec.toLowerCase()) {\n switchMessages.push(`\"${this.sourceUpdater_.codecs[type]}\" -> \"${codecs[type]}\"`);\n }\n });\n\n if (switchMessages.length) {\n this.excludePlaylist({\n playlistToExclude: playlist,\n error: {\n message: `Codec switching not supported: ${switchMessages.join(', ')}.`,\n internal: true\n },\n playlistExclusionDuration: Infinity\n });\n return;\n }\n } // TODO: when using the muxer shouldn't we just return\n // the codecs that the muxer outputs?\n\n\n return codecs;\n }\n /**\n * Create source buffers and exlude any incompatible renditions.\n *\n * @private\n */\n\n\n tryToCreateSourceBuffers_() {\n // media source is not ready yet or sourceBuffers are already\n // created.\n if (this.mediaSource.readyState !== 'open' || this.sourceUpdater_.hasCreatedSourceBuffers()) {\n return;\n }\n\n if (!this.areMediaTypesKnown_()) {\n return;\n }\n\n const codecs = this.getCodecsOrExclude_(); // no codecs means that the playlist was excluded\n\n if (!codecs) {\n return;\n }\n\n this.sourceUpdater_.createSourceBuffers(codecs);\n const codecString = [codecs.video, codecs.audio].filter(Boolean).join(',');\n this.excludeIncompatibleVariants_(codecString);\n }\n /**\n * Excludes playlists with codecs that are unsupported by the muxer and browser.\n */\n\n\n excludeUnsupportedVariants_() {\n const playlists = this.main().playlists;\n const ids = []; // TODO: why don't we have a property to loop through all\n // playlist? Why did we ever mix indexes and keys?\n\n Object.keys(playlists).forEach(key => {\n const variant = playlists[key]; // check if we already processed this playlist.\n\n if (ids.indexOf(variant.id) !== -1) {\n return;\n }\n\n ids.push(variant.id);\n const codecs = codecsForPlaylist(this.main, variant);\n const unsupported = [];\n\n if (codecs.audio && !muxerSupportsCodec(codecs.audio) && !browserSupportsCodec(codecs.audio, this.usingManagedMediaSource_)) {\n unsupported.push(`audio codec ${codecs.audio}`);\n }\n\n if (codecs.video && !muxerSupportsCodec(codecs.video) && !browserSupportsCodec(codecs.video, this.usingManagedMediaSource_)) {\n unsupported.push(`video codec ${codecs.video}`);\n }\n\n if (codecs.text && codecs.text === 'stpp.ttml.im1t') {\n unsupported.push(`text codec ${codecs.text}`);\n }\n\n if (unsupported.length) {\n variant.excludeUntil = Infinity;\n this.logger_(`excluding ${variant.id} for unsupported: ${unsupported.join(', ')}`);\n }\n });\n }\n /**\n * Exclude playlists that are known to be codec or\n * stream-incompatible with the SourceBuffer configuration. For\n * instance, Media Source Extensions would cause the video element to\n * stall waiting for video data if you switched from a variant with\n * video and audio to an audio-only one.\n *\n * @param {Object} media a media playlist compatible with the current\n * set of SourceBuffers. Variants in the current main playlist that\n * do not appear to have compatible codec or stream configurations\n * will be excluded from the default playlist selection algorithm\n * indefinitely.\n * @private\n */\n\n\n excludeIncompatibleVariants_(codecString) {\n const ids = [];\n const playlists = this.main().playlists;\n const codecs = unwrapCodecList(parseCodecs(codecString));\n const codecCount_ = codecCount(codecs);\n const videoDetails = codecs.video && parseCodecs(codecs.video)[0] || null;\n const audioDetails = codecs.audio && parseCodecs(codecs.audio)[0] || null;\n Object.keys(playlists).forEach(key => {\n const variant = playlists[key]; // check if we already processed this playlist.\n // or it if it is already excluded forever.\n\n if (ids.indexOf(variant.id) !== -1 || variant.excludeUntil === Infinity) {\n return;\n }\n\n ids.push(variant.id);\n const exclusionReasons = []; // get codecs from the playlist for this variant\n\n const variantCodecs = codecsForPlaylist(this.mainPlaylistLoader_.main, variant);\n const variantCodecCount = codecCount(variantCodecs); // if no codecs are listed, we cannot determine that this\n // variant is incompatible. Wait for mux.js to probe\n\n if (!variantCodecs.audio && !variantCodecs.video) {\n return;\n } // TODO: we can support this by removing the\n // old media source and creating a new one, but it will take some work.\n // The number of streams cannot change\n\n\n if (variantCodecCount !== codecCount_) {\n exclusionReasons.push(`codec count \"${variantCodecCount}\" !== \"${codecCount_}\"`);\n } // only exclude playlists by codec change, if codecs cannot switch\n // during playback.\n\n\n if (!this.sourceUpdater_.canChangeType()) {\n const variantVideoDetails = variantCodecs.video && parseCodecs(variantCodecs.video)[0] || null;\n const variantAudioDetails = variantCodecs.audio && parseCodecs(variantCodecs.audio)[0] || null; // the video codec cannot change\n\n if (variantVideoDetails && videoDetails && variantVideoDetails.type.toLowerCase() !== videoDetails.type.toLowerCase()) {\n exclusionReasons.push(`video codec \"${variantVideoDetails.type}\" !== \"${videoDetails.type}\"`);\n } // the audio codec cannot change\n\n\n if (variantAudioDetails && audioDetails && variantAudioDetails.type.toLowerCase() !== audioDetails.type.toLowerCase()) {\n exclusionReasons.push(`audio codec \"${variantAudioDetails.type}\" !== \"${audioDetails.type}\"`);\n }\n }\n\n if (exclusionReasons.length) {\n variant.excludeUntil = Infinity;\n this.logger_(`excluding ${variant.id}: ${exclusionReasons.join(' && ')}`);\n }\n });\n }\n\n updateAdCues_(media) {\n let offset = 0;\n const seekable = this.seekable();\n\n if (seekable.length) {\n offset = seekable.start(0);\n }\n\n updateAdCues(media, this.cueTagsTrack_, offset);\n }\n /**\n * Calculates the desired forward buffer length based on current time\n *\n * @return {number} Desired forward buffer length in seconds\n */\n\n\n goalBufferLength() {\n const currentTime = this.tech_.currentTime();\n const initial = Config.GOAL_BUFFER_LENGTH;\n const rate = Config.GOAL_BUFFER_LENGTH_RATE;\n const max = Math.max(initial, Config.MAX_GOAL_BUFFER_LENGTH);\n return Math.min(initial + currentTime * rate, max);\n }\n /**\n * Calculates the desired buffer low water line based on current time\n *\n * @return {number} Desired buffer low water line in seconds\n */\n\n\n bufferLowWaterLine() {\n const currentTime = this.tech_.currentTime();\n const initial = Config.BUFFER_LOW_WATER_LINE;\n const rate = Config.BUFFER_LOW_WATER_LINE_RATE;\n const max = Math.max(initial, Config.MAX_BUFFER_LOW_WATER_LINE);\n const newMax = Math.max(initial, Config.EXPERIMENTAL_MAX_BUFFER_LOW_WATER_LINE);\n return Math.min(initial + currentTime * rate, this.bufferBasedABR ? newMax : max);\n }\n\n bufferHighWaterLine() {\n return Config.BUFFER_HIGH_WATER_LINE;\n }\n\n addDateRangesToTextTrack_(dateRanges) {\n createMetadataTrackIfNotExists(this.inbandTextTracks_, 'com.apple.streaming', this.tech_);\n addDateRangeMetadata({\n inbandTextTracks: this.inbandTextTracks_,\n dateRanges\n });\n }\n\n addMetadataToTextTrack(dispatchType, metadataArray, videoDuration) {\n const timestampOffset = this.sourceUpdater_.videoBuffer ? this.sourceUpdater_.videoTimestampOffset() : this.sourceUpdater_.audioTimestampOffset(); // There's potentially an issue where we could double add metadata if there's a muxed\n // audio/video source with a metadata track, and an alt audio with a metadata track.\n // However, this probably won't happen, and if it does it can be handled then.\n\n createMetadataTrackIfNotExists(this.inbandTextTracks_, dispatchType, this.tech_);\n addMetadata({\n inbandTextTracks: this.inbandTextTracks_,\n metadataArray,\n timestampOffset,\n videoDuration\n });\n }\n /**\n * Utility for getting the pathway or service location from an HLS or DASH playlist.\n *\n * @param {Object} playlist for getting pathway from.\n * @return the pathway attribute of a playlist\n */\n\n\n pathwayAttribute_(playlist) {\n return playlist.attributes['PATHWAY-ID'] || playlist.attributes.serviceLocation;\n }\n /**\n * Initialize available pathways and apply the tag properties.\n */\n\n\n initContentSteeringController_() {\n const main = this.main();\n\n if (!main.contentSteering) {\n return;\n }\n\n for (const playlist of main.playlists) {\n this.contentSteeringController_.addAvailablePathway(this.pathwayAttribute_(playlist));\n }\n\n this.contentSteeringController_.assignTagProperties(main.uri, main.contentSteering); // request the steering manifest immediately if queryBeforeStart is set.\n\n if (this.contentSteeringController_.queryBeforeStart) {\n // When queryBeforeStart is true, initial request should omit steering parameters.\n this.contentSteeringController_.requestSteeringManifest(true);\n return;\n } // otherwise start content steering after playback starts\n\n\n this.tech_.one('canplay', () => {\n this.contentSteeringController_.requestSteeringManifest();\n });\n }\n /**\n * Reset the content steering controller and re-init.\n */\n\n\n resetContentSteeringController_() {\n this.contentSteeringController_.clearAvailablePathways();\n this.contentSteeringController_.dispose();\n this.initContentSteeringController_();\n }\n /**\n * Attaches the listeners for content steering.\n */\n\n\n attachContentSteeringListeners_() {\n this.contentSteeringController_.on('content-steering', this.excludeThenChangePathway_.bind(this));\n const contentSteeringEvents = ['contentsteeringloadstart', 'contentsteeringloadcomplete', 'contentsteeringparsed'];\n contentSteeringEvents.forEach(eventName => {\n this.contentSteeringController_.on(eventName, metadata => {\n this.trigger(_extends({}, metadata));\n });\n });\n\n if (this.sourceType_ === 'dash') {\n this.mainPlaylistLoader_.on('loadedplaylist', () => {\n const main = this.main(); // check if steering tag or pathways changed.\n\n const didDashTagChange = this.contentSteeringController_.didDASHTagChange(main.uri, main.contentSteering);\n\n const didPathwaysChange = () => {\n const availablePathways = this.contentSteeringController_.getAvailablePathways();\n const newPathways = [];\n\n for (const playlist of main.playlists) {\n const serviceLocation = playlist.attributes.serviceLocation;\n\n if (serviceLocation) {\n newPathways.push(serviceLocation);\n\n if (!availablePathways.has(serviceLocation)) {\n return true;\n }\n }\n } // If we have no new serviceLocations and previously had availablePathways\n\n\n if (!newPathways.length && availablePathways.size) {\n return true;\n }\n\n return false;\n };\n\n if (didDashTagChange || didPathwaysChange()) {\n this.resetContentSteeringController_();\n }\n });\n }\n }\n /**\n * Simple exclude and change playlist logic for content steering.\n */\n\n\n excludeThenChangePathway_() {\n const currentPathway = this.contentSteeringController_.getPathway();\n\n if (!currentPathway) {\n return;\n }\n\n this.handlePathwayClones_();\n const main = this.main();\n const playlists = main.playlists;\n const ids = new Set();\n let didEnablePlaylists = false;\n Object.keys(playlists).forEach(key => {\n const variant = playlists[key];\n const pathwayId = this.pathwayAttribute_(variant);\n const differentPathwayId = pathwayId && currentPathway !== pathwayId;\n const steeringExclusion = variant.excludeUntil === Infinity && variant.lastExcludeReason_ === 'content-steering';\n\n if (steeringExclusion && !differentPathwayId) {\n delete variant.excludeUntil;\n delete variant.lastExcludeReason_;\n didEnablePlaylists = true;\n }\n\n const noExcludeUntil = !variant.excludeUntil && variant.excludeUntil !== Infinity;\n const shouldExclude = !ids.has(variant.id) && differentPathwayId && noExcludeUntil;\n\n if (!shouldExclude) {\n return;\n }\n\n ids.add(variant.id);\n variant.excludeUntil = Infinity;\n variant.lastExcludeReason_ = 'content-steering'; // TODO: kind of spammy, maybe move this.\n\n this.logger_(`excluding ${variant.id} for ${variant.lastExcludeReason_}`);\n });\n\n if (this.contentSteeringController_.manifestType_ === 'DASH') {\n Object.keys(this.mediaTypes_).forEach(key => {\n const type = this.mediaTypes_[key];\n\n if (type.activePlaylistLoader) {\n const currentPlaylist = type.activePlaylistLoader.media_; // Check if the current media playlist matches the current CDN\n\n if (currentPlaylist && currentPlaylist.attributes.serviceLocation !== currentPathway) {\n didEnablePlaylists = true;\n }\n }\n });\n }\n\n if (didEnablePlaylists) {\n this.changeSegmentPathway_();\n }\n }\n /**\n * Add, update, or delete playlists and media groups for\n * the pathway clones for HLS Content Steering.\n *\n * See https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/\n *\n * NOTE: Pathway cloning does not currently support the `PER_VARIANT_URIS` and\n * `PER_RENDITION_URIS` as we do not handle `STABLE-VARIANT-ID` or\n * `STABLE-RENDITION-ID` values.\n */\n\n\n handlePathwayClones_() {\n const main = this.main();\n const playlists = main.playlists;\n const currentPathwayClones = this.contentSteeringController_.currentPathwayClones;\n const nextPathwayClones = this.contentSteeringController_.nextPathwayClones;\n const hasClones = currentPathwayClones && currentPathwayClones.size || nextPathwayClones && nextPathwayClones.size;\n\n if (!hasClones) {\n return;\n }\n\n for (const [id, clone] of currentPathwayClones.entries()) {\n const newClone = nextPathwayClones.get(id); // Delete the old pathway clone.\n\n if (!newClone) {\n this.mainPlaylistLoader_.updateOrDeleteClone(clone);\n this.contentSteeringController_.excludePathway(id);\n }\n }\n\n for (const [id, clone] of nextPathwayClones.entries()) {\n const oldClone = currentPathwayClones.get(id); // Create a new pathway if it is a new pathway clone object.\n\n if (!oldClone) {\n const playlistsToClone = playlists.filter(p => {\n return p.attributes['PATHWAY-ID'] === clone['BASE-ID'];\n });\n playlistsToClone.forEach(p => {\n this.mainPlaylistLoader_.addClonePathway(clone, p);\n });\n this.contentSteeringController_.addAvailablePathway(id);\n continue;\n } // There have not been changes to the pathway clone object, so skip.\n\n\n if (this.equalPathwayClones_(oldClone, clone)) {\n continue;\n } // Update a preexisting cloned pathway.\n // True is set for the update flag.\n\n\n this.mainPlaylistLoader_.updateOrDeleteClone(clone, true);\n this.contentSteeringController_.addAvailablePathway(id);\n } // Deep copy contents of next to current pathways.\n\n\n this.contentSteeringController_.currentPathwayClones = new Map(JSON.parse(JSON.stringify([...nextPathwayClones])));\n }\n /**\n * Determines whether two pathway clone objects are equivalent.\n *\n * @param {Object} a The first pathway clone object.\n * @param {Object} b The second pathway clone object.\n * @return {boolean} True if the pathway clone objects are equal, false otherwise.\n */\n\n\n equalPathwayClones_(a, b) {\n if (a['BASE-ID'] !== b['BASE-ID'] || a.ID !== b.ID || a['URI-REPLACEMENT'].HOST !== b['URI-REPLACEMENT'].HOST) {\n return false;\n }\n\n const aParams = a['URI-REPLACEMENT'].PARAMS;\n const bParams = b['URI-REPLACEMENT'].PARAMS; // We need to iterate through both lists of params because one could be\n // missing a parameter that the other has.\n\n for (const p in aParams) {\n if (aParams[p] !== bParams[p]) {\n return false;\n }\n }\n\n for (const p in bParams) {\n if (aParams[p] !== bParams[p]) {\n return false;\n }\n }\n\n return true;\n }\n /**\n * Changes the current playlists for audio, video and subtitles after a new pathway\n * is chosen from content steering.\n */\n\n\n changeSegmentPathway_() {\n const nextPlaylist = this.selectPlaylist();\n this.pauseLoading(); // Switch audio and text track playlists if necessary in DASH\n\n if (this.contentSteeringController_.manifestType_ === 'DASH') {\n this.switchMediaForDASHContentSteering_();\n }\n\n this.switchMedia_(nextPlaylist, 'content-steering');\n }\n /**\n * Iterates through playlists and check their keyId set and compare with the\n * keyStatusMap, only enable playlists that have a usable key. If the playlist\n * has no keyId leave it enabled by default.\n */\n\n\n excludeNonUsablePlaylistsByKeyId_() {\n if (!this.mainPlaylistLoader_ || !this.mainPlaylistLoader_.main) {\n return;\n }\n\n let nonUsableKeyStatusCount = 0;\n const NON_USABLE = 'non-usable';\n this.mainPlaylistLoader_.main.playlists.forEach(playlist => {\n const keyIdSet = this.mainPlaylistLoader_.getKeyIdSet(playlist); // If the playlist doesn't have keyIDs lets not exclude it.\n\n if (!keyIdSet || !keyIdSet.size) {\n return;\n }\n\n keyIdSet.forEach(key => {\n const USABLE = 'usable';\n const hasUsableKeyStatus = this.keyStatusMap_.has(key) && this.keyStatusMap_.get(key) === USABLE;\n const nonUsableExclusion = playlist.lastExcludeReason_ === NON_USABLE && playlist.excludeUntil === Infinity;\n\n if (!hasUsableKeyStatus) {\n // Only exclude playlists that haven't already been excluded as non-usable.\n if (playlist.excludeUntil !== Infinity && playlist.lastExcludeReason_ !== NON_USABLE) {\n playlist.excludeUntil = Infinity;\n playlist.lastExcludeReason_ = NON_USABLE;\n this.logger_(`excluding playlist ${playlist.id} because the key ID ${key} doesn't exist in the keyStatusMap or is not ${USABLE}`);\n } // count all nonUsableKeyStatus\n\n\n nonUsableKeyStatusCount++;\n } else if (hasUsableKeyStatus && nonUsableExclusion) {\n delete playlist.excludeUntil;\n delete playlist.lastExcludeReason_;\n this.logger_(`enabling playlist ${playlist.id} because key ID ${key} is ${USABLE}`);\n }\n });\n }); // If for whatever reason every playlist has a non usable key status. Lets try re-including the SD renditions as a failsafe.\n\n if (nonUsableKeyStatusCount >= this.mainPlaylistLoader_.main.playlists.length) {\n this.mainPlaylistLoader_.main.playlists.forEach(playlist => {\n const isNonHD = playlist && playlist.attributes && playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.height < 720;\n const excludedForNonUsableKey = playlist.excludeUntil === Infinity && playlist.lastExcludeReason_ === NON_USABLE;\n\n if (isNonHD && excludedForNonUsableKey) {\n // Only delete the excludeUntil so we don't try and re-exclude these playlists.\n delete playlist.excludeUntil;\n videojs.log.warn(`enabling non-HD playlist ${playlist.id} because all playlists were excluded due to ${NON_USABLE} key IDs`);\n }\n });\n }\n }\n /**\n * Adds a keystatus to the keystatus map, tries to convert to string if necessary.\n *\n * @param {any} keyId the keyId to add a status for\n * @param {string} status the status of the keyId\n */\n\n\n addKeyStatus_(keyId, status) {\n const isString = typeof keyId === 'string';\n const keyIdHexString = isString ? keyId : bufferToHexString(keyId);\n const formattedKeyIdString = keyIdHexString.slice(0, 32).toLowerCase();\n this.logger_(`KeyStatus '${status}' with key ID ${formattedKeyIdString} added to the keyStatusMap`);\n this.keyStatusMap_.set(formattedKeyIdString, status);\n }\n /**\n * Utility function for adding key status to the keyStatusMap and filtering usable encrypted playlists.\n *\n * @param {any} keyId the keyId from the keystatuschange event\n * @param {string} status the key status string\n */\n\n\n updatePlaylistByKeyStatus(keyId, status) {\n this.addKeyStatus_(keyId, status);\n\n if (!this.waitingForFastQualityPlaylistReceived_) {\n this.excludeNonUsableThenChangePlaylist_();\n } // Listen to loadedplaylist with a single listener and check for new contentProtection elements when a playlist is updated.\n\n\n this.mainPlaylistLoader_.off('loadedplaylist', this.excludeNonUsableThenChangePlaylist_.bind(this));\n this.mainPlaylistLoader_.on('loadedplaylist', this.excludeNonUsableThenChangePlaylist_.bind(this));\n }\n\n excludeNonUsableThenChangePlaylist_() {\n this.excludeNonUsablePlaylistsByKeyId_();\n this.fastQualityChange_();\n }\n\n}\n\n/**\n * Returns a function that acts as the Enable/disable playlist function.\n *\n * @param {PlaylistLoader} loader - The main playlist loader\n * @param {string} playlistID - id of the playlist\n * @param {Function} changePlaylistFn - A function to be called after a\n * playlist's enabled-state has been changed. Will NOT be called if a\n * playlist's enabled-state is unchanged\n * @param {boolean=} enable - Value to set the playlist enabled-state to\n * or if undefined returns the current enabled-state for the playlist\n * @return {Function} Function for setting/getting enabled\n */\n\nconst enableFunction = (loader, playlistID, changePlaylistFn) => enable => {\n const playlist = loader.main.playlists[playlistID];\n const incompatible = isIncompatible(playlist);\n const currentlyEnabled = isEnabled(playlist);\n\n if (typeof enable === 'undefined') {\n return currentlyEnabled;\n }\n\n if (enable) {\n delete playlist.disabled;\n } else {\n playlist.disabled = true;\n }\n\n const metadata = {\n renditionInfo: {\n id: playlistID,\n bandwidth: playlist.attributes.BANDWIDTH,\n resolution: playlist.attributes.RESOLUTION,\n codecs: playlist.attributes.CODECS\n },\n cause: 'fast-quality'\n };\n\n if (enable !== currentlyEnabled && !incompatible) {\n // Ensure the outside world knows about our changes\n if (enable) {\n // call fast quality change only when the playlist is enabled\n changePlaylistFn(playlist);\n loader.trigger({\n type: 'renditionenabled',\n metadata\n });\n } else {\n loader.trigger({\n type: 'renditiondisabled',\n metadata\n });\n }\n }\n\n return enable;\n};\n/**\n * The representation object encapsulates the publicly visible information\n * in a media playlist along with a setter/getter-type function (enabled)\n * for changing the enabled-state of a particular playlist entry\n *\n * @class Representation\n */\n\n\nclass Representation {\n constructor(vhsHandler, playlist, id) {\n const {\n playlistController_: pc\n } = vhsHandler;\n const qualityChangeFunction = pc.fastQualityChange_.bind(pc); // some playlist attributes are optional\n\n if (playlist.attributes) {\n const resolution = playlist.attributes.RESOLUTION;\n this.width = resolution && resolution.width;\n this.height = resolution && resolution.height;\n this.bandwidth = playlist.attributes.BANDWIDTH;\n this.frameRate = playlist.attributes['FRAME-RATE'];\n }\n\n this.codecs = codecsForPlaylist(pc.main(), playlist);\n this.playlist = playlist; // The id is simply the ordinality of the media playlist\n // within the main playlist\n\n this.id = id; // Partially-apply the enableFunction to create a playlist-\n // specific variant\n\n this.enabled = enableFunction(vhsHandler.playlists, playlist.id, qualityChangeFunction);\n }\n\n}\n/**\n * A mixin function that adds the `representations` api to an instance\n * of the VhsHandler class\n *\n * @param {VhsHandler} vhsHandler - An instance of VhsHandler to add the\n * representation API into\n */\n\n\nconst renditionSelectionMixin = function (vhsHandler) {\n // Add a single API-specific function to the VhsHandler instance\n vhsHandler.representations = () => {\n const main = vhsHandler.playlistController_.main();\n const playlists = isAudioOnly(main) ? vhsHandler.playlistController_.getAudioTrackPlaylists_() : main.playlists;\n\n if (!playlists) {\n return [];\n }\n\n return playlists.filter(media => !isIncompatible(media)).map((e, i) => new Representation(vhsHandler, e, e.id));\n };\n};\n\n/**\n * @file playback-watcher.js\n *\n * Playback starts, and now my watch begins. It shall not end until my death. I shall\n * take no wait, hold no uncleared timeouts, father no bad seeks. I shall wear no crowns\n * and win no glory. I shall live and die at my post. I am the corrector of the underflow.\n * I am the watcher of gaps. I am the shield that guards the realms of seekable. I pledge\n * my life and honor to the Playback Watch, for this Player and all the Players to come.\n */\n\nconst timerCancelEvents = ['seeking', 'seeked', 'pause', 'playing', 'error'];\n/**\n * @class PlaybackWatcher\n */\n\nclass PlaybackWatcher extends videojs.EventTarget {\n /**\n * Represents an PlaybackWatcher object.\n *\n * @class\n * @param {Object} options an object that includes the tech and settings\n */\n constructor(options) {\n super();\n this.playlistController_ = options.playlistController;\n this.tech_ = options.tech;\n this.seekable = options.seekable;\n this.allowSeeksWithinUnsafeLiveWindow = options.allowSeeksWithinUnsafeLiveWindow;\n this.liveRangeSafeTimeDelta = options.liveRangeSafeTimeDelta;\n this.media = options.media;\n this.playedRanges_ = [];\n this.consecutiveUpdates = 0;\n this.lastRecordedTime = null;\n this.checkCurrentTimeTimeout_ = null;\n this.logger_ = logger('PlaybackWatcher');\n this.logger_('initialize');\n\n const playHandler = () => this.monitorCurrentTime_();\n\n const canPlayHandler = () => this.monitorCurrentTime_();\n\n const waitingHandler = () => this.techWaiting_();\n\n const cancelTimerHandler = () => this.resetTimeUpdate_();\n\n const pc = this.playlistController_;\n const loaderTypes = ['main', 'subtitle', 'audio'];\n const loaderChecks = {};\n loaderTypes.forEach(type => {\n loaderChecks[type] = {\n reset: () => this.resetSegmentDownloads_(type),\n updateend: () => this.checkSegmentDownloads_(type)\n };\n pc[`${type}SegmentLoader_`].on('appendsdone', loaderChecks[type].updateend); // If a rendition switch happens during a playback stall where the buffer\n // isn't changing we want to reset. We cannot assume that the new rendition\n // will also be stalled, until after new appends.\n\n pc[`${type}SegmentLoader_`].on('playlistupdate', loaderChecks[type].reset); // Playback stalls should not be detected right after seeking.\n // This prevents one segment playlists (single vtt or single segment content)\n // from being detected as stalling. As the buffer will not change in those cases, since\n // the buffer is the entire video duration.\n\n this.tech_.on(['seeked', 'seeking'], loaderChecks[type].reset);\n });\n /**\n * We check if a seek was into a gap through the following steps:\n * 1. We get a seeking event and we do not get a seeked event. This means that\n * a seek was attempted but not completed.\n * 2. We run `fixesBadSeeks_` on segment loader appends. This means that we already\n * removed everything from our buffer and appended a segment, and should be ready\n * to check for gaps.\n */\n\n const setSeekingHandlers = fn => {\n ['main', 'audio'].forEach(type => {\n pc[`${type}SegmentLoader_`][fn]('appended', this.seekingAppendCheck_);\n });\n };\n\n this.seekingAppendCheck_ = () => {\n if (this.fixesBadSeeks_()) {\n this.consecutiveUpdates = 0;\n this.lastRecordedTime = this.tech_.currentTime();\n setSeekingHandlers('off');\n }\n };\n\n this.clearSeekingAppendCheck_ = () => setSeekingHandlers('off');\n\n this.watchForBadSeeking_ = () => {\n this.clearSeekingAppendCheck_();\n setSeekingHandlers('on');\n };\n\n this.tech_.on('seeked', this.clearSeekingAppendCheck_);\n this.tech_.on('seeking', this.watchForBadSeeking_);\n this.tech_.on('waiting', waitingHandler);\n this.tech_.on(timerCancelEvents, cancelTimerHandler);\n this.tech_.on('canplay', canPlayHandler);\n /*\n An edge case exists that results in gaps not being skipped when they exist at the beginning of a stream. This case\n is surfaced in one of two ways:\n 1) The `waiting` event is fired before the player has buffered content, making it impossible\n to find or skip the gap. The `waiting` event is followed by a `play` event. On first play\n we can check if playback is stalled due to a gap, and skip the gap if necessary.\n 2) A source with a gap at the beginning of the stream is loaded programatically while the player\n is in a playing state. To catch this case, it's important that our one-time play listener is setup\n even if the player is in a playing state\n */\n\n this.tech_.one('play', playHandler); // Define the dispose function to clean up our events\n\n this.dispose = () => {\n this.clearSeekingAppendCheck_();\n this.logger_('dispose');\n this.tech_.off('waiting', waitingHandler);\n this.tech_.off(timerCancelEvents, cancelTimerHandler);\n this.tech_.off('canplay', canPlayHandler);\n this.tech_.off('play', playHandler);\n this.tech_.off('seeking', this.watchForBadSeeking_);\n this.tech_.off('seeked', this.clearSeekingAppendCheck_);\n loaderTypes.forEach(type => {\n pc[`${type}SegmentLoader_`].off('appendsdone', loaderChecks[type].updateend);\n pc[`${type}SegmentLoader_`].off('playlistupdate', loaderChecks[type].reset);\n this.tech_.off(['seeked', 'seeking'], loaderChecks[type].reset);\n });\n\n if (this.checkCurrentTimeTimeout_) {\n window$1.clearTimeout(this.checkCurrentTimeTimeout_);\n }\n\n this.resetTimeUpdate_();\n };\n }\n /**\n * Periodically check current time to see if playback stopped\n *\n * @private\n */\n\n\n monitorCurrentTime_() {\n this.checkCurrentTime_();\n\n if (this.checkCurrentTimeTimeout_) {\n window$1.clearTimeout(this.checkCurrentTimeTimeout_);\n } // 42 = 24 fps // 250 is what Webkit uses // FF uses 15\n\n\n this.checkCurrentTimeTimeout_ = window$1.setTimeout(this.monitorCurrentTime_.bind(this), 250);\n }\n /**\n * Reset stalled download stats for a specific type of loader\n *\n * @param {string} type\n * The segment loader type to check.\n *\n * @listens SegmentLoader#playlistupdate\n * @listens Tech#seeking\n * @listens Tech#seeked\n */\n\n\n resetSegmentDownloads_(type) {\n const loader = this.playlistController_[`${type}SegmentLoader_`];\n\n if (this[`${type}StalledDownloads_`] > 0) {\n this.logger_(`resetting possible stalled download count for ${type} loader`);\n }\n\n this[`${type}StalledDownloads_`] = 0;\n this[`${type}Buffered_`] = loader.buffered_();\n }\n /**\n * Checks on every segment `appendsdone` to see\n * if segment appends are making progress. If they are not\n * and we are still downloading bytes. We exclude the playlist.\n *\n * @param {string} type\n * The segment loader type to check.\n *\n * @listens SegmentLoader#appendsdone\n */\n\n\n checkSegmentDownloads_(type) {\n const pc = this.playlistController_;\n const loader = pc[`${type}SegmentLoader_`];\n const buffered = loader.buffered_();\n const isBufferedDifferent = isRangeDifferent(this[`${type}Buffered_`], buffered);\n this[`${type}Buffered_`] = buffered; // if another watcher is going to fix the issue or\n // the buffered value for this loader changed\n // appends are working\n\n if (isBufferedDifferent) {\n const metadata = {\n bufferedRanges: buffered\n };\n pc.trigger({\n type: 'bufferedrangeschanged',\n metadata\n });\n this.resetSegmentDownloads_(type);\n return;\n }\n\n this[`${type}StalledDownloads_`]++;\n this.logger_(`found #${this[`${type}StalledDownloads_`]} ${type} appends that did not increase buffer (possible stalled download)`, {\n playlistId: loader.playlist_ && loader.playlist_.id,\n buffered: timeRangesToArray(buffered)\n }); // after 10 possibly stalled appends with no reset, exclude\n\n if (this[`${type}StalledDownloads_`] < 10) {\n return;\n }\n\n this.logger_(`${type} loader stalled download exclusion`);\n this.resetSegmentDownloads_(type);\n this.tech_.trigger({\n type: 'usage',\n name: `vhs-${type}-download-exclusion`\n });\n\n if (type === 'subtitle') {\n return;\n } // TODO: should we exclude audio tracks rather than main tracks\n // when type is audio?\n\n\n pc.excludePlaylist({\n error: {\n message: `Excessive ${type} segment downloading detected.`\n },\n playlistExclusionDuration: Infinity\n });\n }\n /**\n * The purpose of this function is to emulate the \"waiting\" event on\n * browsers that do not emit it when they are waiting for more\n * data to continue playback\n *\n * @private\n */\n\n\n checkCurrentTime_() {\n if (this.tech_.paused() || this.tech_.seeking()) {\n return;\n }\n\n const currentTime = this.tech_.currentTime();\n const buffered = this.tech_.buffered();\n\n if (this.lastRecordedTime === currentTime && (!buffered.length || currentTime + SAFE_TIME_DELTA >= buffered.end(buffered.length - 1))) {\n // If current time is at the end of the final buffered region, then any playback\n // stall is most likely caused by buffering in a low bandwidth environment. The tech\n // should fire a `waiting` event in this scenario, but due to browser and tech\n // inconsistencies. Calling `techWaiting_` here allows us to simulate\n // responding to a native `waiting` event when the tech fails to emit one.\n return this.techWaiting_();\n }\n\n if (this.consecutiveUpdates >= 5 && currentTime === this.lastRecordedTime) {\n this.consecutiveUpdates++;\n this.waiting_();\n } else if (currentTime === this.lastRecordedTime) {\n this.consecutiveUpdates++;\n } else {\n this.playedRanges_.push(createTimeRanges([this.lastRecordedTime, currentTime]));\n const metadata = {\n playedRanges: this.playedRanges_\n };\n this.playlistController_.trigger({\n type: 'playedrangeschanged',\n metadata\n });\n this.consecutiveUpdates = 0;\n this.lastRecordedTime = currentTime;\n }\n }\n /**\n * Resets the 'timeupdate' mechanism designed to detect that we are stalled\n *\n * @private\n */\n\n\n resetTimeUpdate_() {\n this.consecutiveUpdates = 0;\n }\n /**\n * Fixes situations where there's a bad seek\n *\n * @return {boolean} whether an action was taken to fix the seek\n * @private\n */\n\n\n fixesBadSeeks_() {\n const seeking = this.tech_.seeking();\n\n if (!seeking) {\n return false;\n } // TODO: It's possible that these seekable checks should be moved out of this function\n // and into a function that runs on seekablechange. It's also possible that we only need\n // afterSeekableWindow as the buffered check at the bottom is good enough to handle before\n // seekable range.\n\n\n const seekable = this.seekable();\n const currentTime = this.tech_.currentTime();\n const isAfterSeekableRange = this.afterSeekableWindow_(seekable, currentTime, this.media(), this.allowSeeksWithinUnsafeLiveWindow);\n let seekTo;\n\n if (isAfterSeekableRange) {\n const seekableEnd = seekable.end(seekable.length - 1); // sync to live point (if VOD, our seekable was updated and we're simply adjusting)\n\n seekTo = seekableEnd;\n }\n\n if (this.beforeSeekableWindow_(seekable, currentTime)) {\n const seekableStart = seekable.start(0); // sync to the beginning of the live window\n // provide a buffer of .1 seconds to handle rounding/imprecise numbers\n\n seekTo = seekableStart + ( // if the playlist is too short and the seekable range is an exact time (can\n // happen in live with a 3 segment playlist), then don't use a time delta\n seekableStart === seekable.end(0) ? 0 : SAFE_TIME_DELTA);\n }\n\n if (typeof seekTo !== 'undefined') {\n this.logger_(`Trying to seek outside of seekable at time ${currentTime} with ` + `seekable range ${printableRange(seekable)}. Seeking to ` + `${seekTo}.`);\n this.tech_.setCurrentTime(seekTo);\n return true;\n }\n\n const sourceUpdater = this.playlistController_.sourceUpdater_;\n const buffered = this.tech_.buffered();\n const audioBuffered = sourceUpdater.audioBuffer ? sourceUpdater.audioBuffered() : null;\n const videoBuffered = sourceUpdater.videoBuffer ? sourceUpdater.videoBuffered() : null;\n const media = this.media(); // verify that at least two segment durations or one part duration have been\n // appended before checking for a gap.\n\n const minAppendedDuration = media.partTargetDuration ? media.partTargetDuration : (media.targetDuration - TIME_FUDGE_FACTOR) * 2; // verify that at least two segment durations have been\n // appended before checking for a gap.\n\n const bufferedToCheck = [audioBuffered, videoBuffered];\n\n for (let i = 0; i < bufferedToCheck.length; i++) {\n // skip null buffered\n if (!bufferedToCheck[i]) {\n continue;\n }\n\n const timeAhead = timeAheadOf(bufferedToCheck[i], currentTime); // if we are less than two video/audio segment durations or one part\n // duration behind we haven't appended enough to call this a bad seek.\n\n if (timeAhead < minAppendedDuration) {\n return false;\n }\n }\n\n const nextRange = findNextRange(buffered, currentTime); // we have appended enough content, but we don't have anything buffered\n // to seek over the gap\n\n if (nextRange.length === 0) {\n return false;\n }\n\n seekTo = nextRange.start(0) + SAFE_TIME_DELTA;\n this.logger_(`Buffered region starts (${nextRange.start(0)}) ` + ` just beyond seek point (${currentTime}). Seeking to ${seekTo}.`);\n this.tech_.setCurrentTime(seekTo);\n return true;\n }\n /**\n * Handler for situations when we determine the player is waiting.\n *\n * @private\n */\n\n\n waiting_() {\n if (this.techWaiting_()) {\n return;\n } // All tech waiting checks failed. Use last resort correction\n\n\n const currentTime = this.tech_.currentTime();\n const buffered = this.tech_.buffered();\n const currentRange = findRange(buffered, currentTime); // Sometimes the player can stall for unknown reasons within a contiguous buffered\n // region with no indication that anything is amiss (seen in Firefox). Seeking to\n // currentTime is usually enough to kickstart the player. This checks that the player\n // is currently within a buffered region before attempting a corrective seek.\n // Chrome does not appear to continue `timeupdate` events after a `waiting` event\n // until there is ~ 3 seconds of forward buffer available. PlaybackWatcher should also\n // make sure there is ~3 seconds of forward buffer before taking any corrective action\n // to avoid triggering an `unknownwaiting` event when the network is slow.\n\n if (currentRange.length && currentTime + 3 <= currentRange.end(0)) {\n this.resetTimeUpdate_();\n this.tech_.setCurrentTime(currentTime);\n this.logger_(`Stopped at ${currentTime} while inside a buffered region ` + `[${currentRange.start(0)} -> ${currentRange.end(0)}]. Attempting to resume ` + 'playback by seeking to the current time.'); // unknown waiting corrections may be useful for monitoring QoS\n\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-unknown-waiting'\n });\n return;\n }\n }\n /**\n * Handler for situations when the tech fires a `waiting` event\n *\n * @return {boolean}\n * True if an action (or none) was needed to correct the waiting. False if no\n * checks passed\n * @private\n */\n\n\n techWaiting_() {\n const seekable = this.seekable();\n const currentTime = this.tech_.currentTime();\n\n if (this.tech_.seeking()) {\n // Tech is seeking or already waiting on another action, no action needed\n return true;\n }\n\n if (this.beforeSeekableWindow_(seekable, currentTime)) {\n const livePoint = seekable.end(seekable.length - 1);\n this.logger_(`Fell out of live window at time ${currentTime}. Seeking to ` + `live point (seekable end) ${livePoint}`);\n this.resetTimeUpdate_();\n this.tech_.setCurrentTime(livePoint); // live window resyncs may be useful for monitoring QoS\n\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-live-resync'\n });\n return true;\n }\n\n const sourceUpdater = this.tech_.vhs.playlistController_.sourceUpdater_;\n const buffered = this.tech_.buffered();\n const videoUnderflow = this.videoUnderflow_({\n audioBuffered: sourceUpdater.audioBuffered(),\n videoBuffered: sourceUpdater.videoBuffered(),\n currentTime\n });\n\n if (videoUnderflow) {\n // Even though the video underflowed and was stuck in a gap, the audio overplayed\n // the gap, leading currentTime into a buffered range. Seeking to currentTime\n // allows the video to catch up to the audio position without losing any audio\n // (only suffering ~3 seconds of frozen video and a pause in audio playback).\n this.resetTimeUpdate_();\n this.tech_.setCurrentTime(currentTime); // video underflow may be useful for monitoring QoS\n\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-video-underflow'\n });\n return true;\n }\n\n const nextRange = findNextRange(buffered, currentTime); // check for gap\n\n if (nextRange.length > 0) {\n this.logger_(`Stopped at ${currentTime} and seeking to ${nextRange.start(0)}`);\n this.resetTimeUpdate_();\n this.skipTheGap_(currentTime);\n return true;\n } // All checks failed. Returning false to indicate failure to correct waiting\n\n\n return false;\n }\n\n afterSeekableWindow_(seekable, currentTime, playlist, allowSeeksWithinUnsafeLiveWindow = false) {\n if (!seekable.length) {\n // we can't make a solid case if there's no seekable, default to false\n return false;\n }\n\n let allowedEnd = seekable.end(seekable.length - 1) + SAFE_TIME_DELTA;\n const isLive = !playlist.endList;\n const isLLHLS = typeof playlist.partTargetDuration === 'number';\n\n if (isLive && (isLLHLS || allowSeeksWithinUnsafeLiveWindow)) {\n allowedEnd = seekable.end(seekable.length - 1) + playlist.targetDuration * 3;\n }\n\n if (currentTime > allowedEnd) {\n return true;\n }\n\n return false;\n }\n\n beforeSeekableWindow_(seekable, currentTime) {\n if (seekable.length && // can't fall before 0 and 0 seekable start identifies VOD stream\n seekable.start(0) > 0 && currentTime < seekable.start(0) - this.liveRangeSafeTimeDelta) {\n return true;\n }\n\n return false;\n }\n\n videoUnderflow_({\n videoBuffered,\n audioBuffered,\n currentTime\n }) {\n // audio only content will not have video underflow :)\n if (!videoBuffered) {\n return;\n }\n\n let gap; // find a gap in demuxed content.\n\n if (videoBuffered.length && audioBuffered.length) {\n // in Chrome audio will continue to play for ~3s when we run out of video\n // so we have to check that the video buffer did have some buffer in the\n // past.\n const lastVideoRange = findRange(videoBuffered, currentTime - 3);\n const videoRange = findRange(videoBuffered, currentTime);\n const audioRange = findRange(audioBuffered, currentTime);\n\n if (audioRange.length && !videoRange.length && lastVideoRange.length) {\n gap = {\n start: lastVideoRange.end(0),\n end: audioRange.end(0)\n };\n } // find a gap in muxed content.\n\n } else {\n const nextRange = findNextRange(videoBuffered, currentTime); // Even if there is no available next range, there is still a possibility we are\n // stuck in a gap due to video underflow.\n\n if (!nextRange.length) {\n gap = this.gapFromVideoUnderflow_(videoBuffered, currentTime);\n }\n }\n\n if (gap) {\n this.logger_(`Encountered a gap in video from ${gap.start} to ${gap.end}. ` + `Seeking to current time ${currentTime}`);\n return true;\n }\n\n return false;\n }\n /**\n * Timer callback. If playback still has not proceeded, then we seek\n * to the start of the next buffered region.\n *\n * @private\n */\n\n\n skipTheGap_(scheduledCurrentTime) {\n const buffered = this.tech_.buffered();\n const currentTime = this.tech_.currentTime();\n const nextRange = findNextRange(buffered, currentTime);\n this.resetTimeUpdate_();\n\n if (nextRange.length === 0 || currentTime !== scheduledCurrentTime) {\n return;\n }\n\n this.logger_('skipTheGap_:', 'currentTime:', currentTime, 'scheduled currentTime:', scheduledCurrentTime, 'nextRange start:', nextRange.start(0)); // only seek if we still have not played\n\n this.tech_.setCurrentTime(nextRange.start(0) + TIME_FUDGE_FACTOR);\n const metadata = {\n gapInfo: {\n from: currentTime,\n to: nextRange.start(0)\n }\n };\n this.playlistController_.trigger({\n type: 'gapjumped',\n metadata\n });\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-gap-skip'\n });\n }\n\n gapFromVideoUnderflow_(buffered, currentTime) {\n // At least in Chrome, if there is a gap in the video buffer, the audio will continue\n // playing for ~3 seconds after the video gap starts. This is done to account for\n // video buffer underflow/underrun (note that this is not done when there is audio\n // buffer underflow/underrun -- in that case the video will stop as soon as it\n // encounters the gap, as audio stalls are more noticeable/jarring to a user than\n // video stalls). The player's time will reflect the playthrough of audio, so the\n // time will appear as if we are in a buffered region, even if we are stuck in a\n // \"gap.\"\n //\n // Example:\n // video buffer: 0 => 10.1, 10.2 => 20\n // audio buffer: 0 => 20\n // overall buffer: 0 => 10.1, 10.2 => 20\n // current time: 13\n //\n // Chrome's video froze at 10 seconds, where the video buffer encountered the gap,\n // however, the audio continued playing until it reached ~3 seconds past the gap\n // (13 seconds), at which point it stops as well. Since current time is past the\n // gap, findNextRange will return no ranges.\n //\n // To check for this issue, we see if there is a gap that starts somewhere within\n // a 3 second range (3 seconds +/- 1 second) back from our current time.\n const gaps = findGaps(buffered);\n\n for (let i = 0; i < gaps.length; i++) {\n const start = gaps.start(i);\n const end = gaps.end(i); // gap is starts no more than 4 seconds back\n\n if (currentTime - start < 4 && currentTime - start > 2) {\n return {\n start,\n end\n };\n }\n }\n\n return null;\n }\n\n}\n\nconst defaultOptions = {\n errorInterval: 30,\n\n getSource(next) {\n const tech = this.tech({\n IWillNotUseThisInPlugins: true\n });\n const sourceObj = tech.currentSource_ || this.currentSource();\n return next(sourceObj);\n }\n\n};\n/**\n * Main entry point for the plugin\n *\n * @param {Player} player a reference to a videojs Player instance\n * @param {Object} [options] an object with plugin options\n * @private\n */\n\nconst initPlugin = function (player, options) {\n let lastCalled = 0;\n let seekTo = 0;\n const localOptions = merge(defaultOptions, options);\n player.ready(() => {\n player.trigger({\n type: 'usage',\n name: 'vhs-error-reload-initialized'\n });\n });\n /**\n * Player modifications to perform that must wait until `loadedmetadata`\n * has been triggered\n *\n * @private\n */\n\n const loadedMetadataHandler = function () {\n if (seekTo) {\n player.currentTime(seekTo);\n }\n };\n /**\n * Set the source on the player element, play, and seek if necessary\n *\n * @param {Object} sourceObj An object specifying the source url and mime-type to play\n * @private\n */\n\n\n const setSource = function (sourceObj) {\n if (sourceObj === null || sourceObj === undefined) {\n return;\n }\n\n seekTo = player.duration() !== Infinity && player.currentTime() || 0;\n player.one('loadedmetadata', loadedMetadataHandler);\n player.src(sourceObj);\n player.trigger({\n type: 'usage',\n name: 'vhs-error-reload'\n });\n player.play();\n };\n /**\n * Attempt to get a source from either the built-in getSource function\n * or a custom function provided via the options\n *\n * @private\n */\n\n\n const errorHandler = function () {\n // Do not attempt to reload the source if a source-reload occurred before\n // 'errorInterval' time has elapsed since the last source-reload\n if (Date.now() - lastCalled < localOptions.errorInterval * 1000) {\n player.trigger({\n type: 'usage',\n name: 'vhs-error-reload-canceled'\n });\n return;\n }\n\n if (!localOptions.getSource || typeof localOptions.getSource !== 'function') {\n videojs.log.error('ERROR: reloadSourceOnError - The option getSource must be a function!');\n return;\n }\n\n lastCalled = Date.now();\n return localOptions.getSource.call(player, setSource);\n };\n /**\n * Unbind any event handlers that were bound by the plugin\n *\n * @private\n */\n\n\n const cleanupEvents = function () {\n player.off('loadedmetadata', loadedMetadataHandler);\n player.off('error', errorHandler);\n player.off('dispose', cleanupEvents);\n };\n /**\n * Cleanup before re-initializing the plugin\n *\n * @param {Object} [newOptions] an object with plugin options\n * @private\n */\n\n\n const reinitPlugin = function (newOptions) {\n cleanupEvents();\n initPlugin(player, newOptions);\n };\n\n player.on('error', errorHandler);\n player.on('dispose', cleanupEvents); // Overwrite the plugin function so that we can correctly cleanup before\n // initializing the plugin\n\n player.reloadSourceOnError = reinitPlugin;\n};\n/**\n * Reload the source when an error is detected as long as there\n * wasn't an error previously within the last 30 seconds\n *\n * @param {Object} [options] an object with plugin options\n */\n\n\nconst reloadSourceOnError = function (options) {\n initPlugin(this, options);\n};\n\nvar version$4 = \"3.16.2\";\n\nvar version$3 = \"7.1.0\";\n\nvar version$2 = \"1.3.1\";\n\nvar version$1 = \"7.2.0\";\n\nvar version = \"4.0.2\";\n\nconst Vhs = {\n PlaylistLoader,\n Playlist,\n utils,\n STANDARD_PLAYLIST_SELECTOR: lastBandwidthSelector,\n INITIAL_PLAYLIST_SELECTOR: lowestBitrateCompatibleVariantSelector,\n lastBandwidthSelector,\n movingAverageBandwidthSelector,\n comparePlaylistBandwidth,\n comparePlaylistResolution,\n xhr: xhrFactory()\n}; // Define getter/setters for config properties\n\nObject.keys(Config).forEach(prop => {\n Object.defineProperty(Vhs, prop, {\n get() {\n videojs.log.warn(`using Vhs.${prop} is UNSAFE be sure you know what you are doing`);\n return Config[prop];\n },\n\n set(value) {\n videojs.log.warn(`using Vhs.${prop} is UNSAFE be sure you know what you are doing`);\n\n if (typeof value !== 'number' || value < 0) {\n videojs.log.warn(`value of Vhs.${prop} must be greater than or equal to 0`);\n return;\n }\n\n Config[prop] = value;\n }\n\n });\n});\nconst LOCAL_STORAGE_KEY = 'videojs-vhs';\n/**\n * Updates the selectedIndex of the QualityLevelList when a mediachange happens in vhs.\n *\n * @param {QualityLevelList} qualityLevels The QualityLevelList to update.\n * @param {PlaylistLoader} playlistLoader PlaylistLoader containing the new media info.\n * @function handleVhsMediaChange\n */\n\nconst handleVhsMediaChange = function (qualityLevels, playlistLoader) {\n const newPlaylist = playlistLoader.media();\n let selectedIndex = -1;\n\n for (let i = 0; i < qualityLevels.length; i++) {\n if (qualityLevels[i].id === newPlaylist.id) {\n selectedIndex = i;\n break;\n }\n }\n\n qualityLevels.selectedIndex_ = selectedIndex;\n qualityLevels.trigger({\n selectedIndex,\n type: 'change'\n });\n};\n/**\n * Adds quality levels to list once playlist metadata is available\n *\n * @param {QualityLevelList} qualityLevels The QualityLevelList to attach events to.\n * @param {Object} vhs Vhs object to listen to for media events.\n * @function handleVhsLoadedMetadata\n */\n\n\nconst handleVhsLoadedMetadata = function (qualityLevels, vhs) {\n vhs.representations().forEach(rep => {\n qualityLevels.addQualityLevel(rep);\n });\n handleVhsMediaChange(qualityLevels, vhs.playlists);\n}; // VHS is a source handler, not a tech. Make sure attempts to use it\n// as one do not cause exceptions.\n\n\nVhs.canPlaySource = function () {\n return videojs.log.warn('VHS is no longer a tech. Please remove it from ' + 'your player\\'s techOrder.');\n};\n\nconst emeKeySystems = (keySystemOptions, mainPlaylist, audioPlaylist) => {\n if (!keySystemOptions) {\n return keySystemOptions;\n }\n\n let codecs = {};\n\n if (mainPlaylist && mainPlaylist.attributes && mainPlaylist.attributes.CODECS) {\n codecs = unwrapCodecList(parseCodecs(mainPlaylist.attributes.CODECS));\n }\n\n if (audioPlaylist && audioPlaylist.attributes && audioPlaylist.attributes.CODECS) {\n codecs.audio = audioPlaylist.attributes.CODECS;\n }\n\n const videoContentType = getMimeForCodec(codecs.video);\n const audioContentType = getMimeForCodec(codecs.audio); // upsert the content types based on the selected playlist\n\n const keySystemContentTypes = {};\n\n for (const keySystem in keySystemOptions) {\n keySystemContentTypes[keySystem] = {};\n\n if (audioContentType) {\n keySystemContentTypes[keySystem].audioContentType = audioContentType;\n }\n\n if (videoContentType) {\n keySystemContentTypes[keySystem].videoContentType = videoContentType;\n } // Default to using the video playlist's PSSH even though they may be different, as\n // videojs-contrib-eme will only accept one in the options.\n //\n // This shouldn't be an issue for most cases as early intialization will handle all\n // unique PSSH values, and if they aren't, then encrypted events should have the\n // specific information needed for the unique license.\n\n\n if (mainPlaylist.contentProtection && mainPlaylist.contentProtection[keySystem] && mainPlaylist.contentProtection[keySystem].pssh) {\n keySystemContentTypes[keySystem].pssh = mainPlaylist.contentProtection[keySystem].pssh;\n } // videojs-contrib-eme accepts the option of specifying: 'com.some.cdm': 'url'\n // so we need to prevent overwriting the URL entirely\n\n\n if (typeof keySystemOptions[keySystem] === 'string') {\n keySystemContentTypes[keySystem].url = keySystemOptions[keySystem];\n }\n }\n\n return merge(keySystemOptions, keySystemContentTypes);\n};\n/**\n * @typedef {Object} KeySystems\n *\n * keySystems configuration for https://github.com/videojs/videojs-contrib-eme\n * Note: not all options are listed here.\n *\n * @property {Uint8Array} [pssh]\n * Protection System Specific Header\n */\n\n/**\n * Goes through all the playlists and collects an array of KeySystems options objects\n * containing each playlist's keySystems and their pssh values, if available.\n *\n * @param {Object[]} playlists\n * The playlists to look through\n * @param {string[]} keySystems\n * The keySystems to collect pssh values for\n *\n * @return {KeySystems[]}\n * An array of KeySystems objects containing available key systems and their\n * pssh values\n */\n\n\nconst getAllPsshKeySystemsOptions = (playlists, keySystems) => {\n return playlists.reduce((keySystemsArr, playlist) => {\n if (!playlist.contentProtection) {\n return keySystemsArr;\n }\n\n const keySystemsOptions = keySystems.reduce((keySystemsObj, keySystem) => {\n const keySystemOptions = playlist.contentProtection[keySystem];\n\n if (keySystemOptions && keySystemOptions.pssh) {\n keySystemsObj[keySystem] = {\n pssh: keySystemOptions.pssh\n };\n }\n\n return keySystemsObj;\n }, {});\n\n if (Object.keys(keySystemsOptions).length) {\n keySystemsArr.push(keySystemsOptions);\n }\n\n return keySystemsArr;\n }, []);\n};\n/**\n * Returns a promise that waits for the\n * [eme plugin](https://github.com/videojs/videojs-contrib-eme) to create a key session.\n *\n * Works around https://bugs.chromium.org/p/chromium/issues/detail?id=895449 in non-IE11\n * browsers.\n *\n * As per the above ticket, this is particularly important for Chrome, where, if\n * unencrypted content is appended before encrypted content and the key session has not\n * been created, a MEDIA_ERR_DECODE will be thrown once the encrypted content is reached\n * during playback.\n *\n * @param {Object} player\n * The player instance\n * @param {Object[]} sourceKeySystems\n * The key systems options from the player source\n * @param {Object} [audioMedia]\n * The active audio media playlist (optional)\n * @param {Object[]} mainPlaylists\n * The playlists found on the main playlist object\n *\n * @return {Object}\n * Promise that resolves when the key session has been created\n */\n\n\nconst waitForKeySessionCreation = ({\n player,\n sourceKeySystems,\n audioMedia,\n mainPlaylists\n}) => {\n if (!player.eme.initializeMediaKeys) {\n return Promise.resolve();\n } // TODO should all audio PSSH values be initialized for DRM?\n //\n // All unique video rendition pssh values are initialized for DRM, but here only\n // the initial audio playlist license is initialized. In theory, an encrypted\n // event should be fired if the user switches to an alternative audio playlist\n // where a license is required, but this case hasn't yet been tested. In addition, there\n // may be many alternate audio playlists unlikely to be used (e.g., multiple different\n // languages).\n\n\n const playlists = audioMedia ? mainPlaylists.concat([audioMedia]) : mainPlaylists;\n const keySystemsOptionsArr = getAllPsshKeySystemsOptions(playlists, Object.keys(sourceKeySystems));\n const initializationFinishedPromises = [];\n const keySessionCreatedPromises = []; // Since PSSH values are interpreted as initData, EME will dedupe any duplicates. The\n // only place where it should not be deduped is for ms-prefixed APIs, but\n // the existence of modern EME APIs in addition to\n // ms-prefixed APIs on Edge should prevent this from being a concern.\n // initializeMediaKeys also won't use the webkit-prefixed APIs.\n\n keySystemsOptionsArr.forEach(keySystemsOptions => {\n keySessionCreatedPromises.push(new Promise((resolve, reject) => {\n player.tech_.one('keysessioncreated', resolve);\n }));\n initializationFinishedPromises.push(new Promise((resolve, reject) => {\n player.eme.initializeMediaKeys({\n keySystems: keySystemsOptions\n }, err => {\n if (err) {\n reject(err);\n return;\n }\n\n resolve();\n });\n }));\n }); // The reasons Promise.race is chosen over Promise.any:\n //\n // * Promise.any is only available in Safari 14+.\n // * None of these promises are expected to reject. If they do reject, it might be\n // better here for the race to surface the rejection, rather than mask it by using\n // Promise.any.\n\n return Promise.race([// If a session was previously created, these will all finish resolving without\n // creating a new session, otherwise it will take until the end of all license\n // requests, which is why the key session check is used (to make setup much faster).\n Promise.all(initializationFinishedPromises), // Once a single session is created, the browser knows DRM will be used.\n Promise.race(keySessionCreatedPromises)]);\n};\n/**\n * If the [eme](https://github.com/videojs/videojs-contrib-eme) plugin is available, and\n * there are keySystems on the source, sets up source options to prepare the source for\n * eme.\n *\n * @param {Object} player\n * The player instance\n * @param {Object[]} sourceKeySystems\n * The key systems options from the player source\n * @param {Object} media\n * The active media playlist\n * @param {Object} [audioMedia]\n * The active audio media playlist (optional)\n *\n * @return {boolean}\n * Whether or not options were configured and EME is available\n */\n\nconst setupEmeOptions = ({\n player,\n sourceKeySystems,\n media,\n audioMedia\n}) => {\n const sourceOptions = emeKeySystems(sourceKeySystems, media, audioMedia);\n\n if (!sourceOptions) {\n return false;\n }\n\n player.currentSource().keySystems = sourceOptions; // eme handles the rest of the setup, so if it is missing\n // do nothing.\n\n if (sourceOptions && !player.eme) {\n videojs.log.warn('DRM encrypted source cannot be decrypted without a DRM plugin');\n return false;\n }\n\n return true;\n};\n\nconst getVhsLocalStorage = () => {\n if (!window$1.localStorage) {\n return null;\n }\n\n const storedObject = window$1.localStorage.getItem(LOCAL_STORAGE_KEY);\n\n if (!storedObject) {\n return null;\n }\n\n try {\n return JSON.parse(storedObject);\n } catch (e) {\n // someone may have tampered with the value\n return null;\n }\n};\n\nconst updateVhsLocalStorage = options => {\n if (!window$1.localStorage) {\n return false;\n }\n\n let objectToStore = getVhsLocalStorage();\n objectToStore = objectToStore ? merge(objectToStore, options) : options;\n\n try {\n window$1.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(objectToStore));\n } catch (e) {\n // Throws if storage is full (e.g., always on iOS 5+ Safari private mode, where\n // storage is set to 0).\n // https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem#Exceptions\n // No need to perform any operation.\n return false;\n }\n\n return objectToStore;\n};\n/**\n * Parses VHS-supported media types from data URIs. See\n * https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n * for information on data URIs.\n *\n * @param {string} dataUri\n * The data URI\n *\n * @return {string|Object}\n * The parsed object/string, or the original string if no supported media type\n * was found\n */\n\n\nconst expandDataUri = dataUri => {\n if (dataUri.toLowerCase().indexOf('data:application/vnd.videojs.vhs+json,') === 0) {\n return JSON.parse(dataUri.substring(dataUri.indexOf(',') + 1));\n } // no known case for this data URI, return the string as-is\n\n\n return dataUri;\n};\n/**\n * Adds a request hook to an xhr object\n *\n * @param {Object} xhr object to add the onRequest hook to\n * @param {function} callback hook function for an xhr request\n */\n\n\nconst addOnRequestHook = (xhr, callback) => {\n if (!xhr._requestCallbackSet) {\n xhr._requestCallbackSet = new Set();\n }\n\n xhr._requestCallbackSet.add(callback);\n};\n/**\n * Adds a response hook to an xhr object\n *\n * @param {Object} xhr object to add the onResponse hook to\n * @param {function} callback hook function for an xhr response\n */\n\n\nconst addOnResponseHook = (xhr, callback) => {\n if (!xhr._responseCallbackSet) {\n xhr._responseCallbackSet = new Set();\n }\n\n xhr._responseCallbackSet.add(callback);\n};\n/**\n * Removes a request hook on an xhr object, deletes the onRequest set if empty.\n *\n * @param {Object} xhr object to remove the onRequest hook from\n * @param {function} callback hook function to remove\n */\n\n\nconst removeOnRequestHook = (xhr, callback) => {\n if (!xhr._requestCallbackSet) {\n return;\n }\n\n xhr._requestCallbackSet.delete(callback);\n\n if (!xhr._requestCallbackSet.size) {\n delete xhr._requestCallbackSet;\n }\n};\n/**\n * Removes a response hook on an xhr object, deletes the onResponse set if empty.\n *\n * @param {Object} xhr object to remove the onResponse hook from\n * @param {function} callback hook function to remove\n */\n\n\nconst removeOnResponseHook = (xhr, callback) => {\n if (!xhr._responseCallbackSet) {\n return;\n }\n\n xhr._responseCallbackSet.delete(callback);\n\n if (!xhr._responseCallbackSet.size) {\n delete xhr._responseCallbackSet;\n }\n};\n/**\n * Whether the browser has built-in HLS support.\n */\n\n\nVhs.supportsNativeHls = function () {\n if (!document || !document.createElement) {\n return false;\n }\n\n const video = document.createElement('video'); // native HLS is definitely not supported if HTML5 video isn't\n\n if (!videojs.getTech('Html5').isSupported()) {\n return false;\n } // HLS manifests can go by many mime-types\n\n\n const canPlay = [// Apple santioned\n 'application/vnd.apple.mpegurl', // Apple sanctioned for backwards compatibility\n 'audio/mpegurl', // Very common\n 'audio/x-mpegurl', // Very common\n 'application/x-mpegurl', // Included for completeness\n 'video/x-mpegurl', 'video/mpegurl', 'application/mpegurl'];\n return canPlay.some(function (canItPlay) {\n return /maybe|probably/i.test(video.canPlayType(canItPlay));\n });\n}();\n\nVhs.supportsNativeDash = function () {\n if (!document || !document.createElement || !videojs.getTech('Html5').isSupported()) {\n return false;\n }\n\n return /maybe|probably/i.test(document.createElement('video').canPlayType('application/dash+xml'));\n}();\n\nVhs.supportsTypeNatively = type => {\n if (type === 'hls') {\n return Vhs.supportsNativeHls;\n }\n\n if (type === 'dash') {\n return Vhs.supportsNativeDash;\n }\n\n return false;\n};\n/**\n * VHS is a source handler, not a tech. Make sure attempts to use it\n * as one do not cause exceptions.\n */\n\n\nVhs.isSupported = function () {\n return videojs.log.warn('VHS is no longer a tech. Please remove it from ' + 'your player\\'s techOrder.');\n};\n/**\n * A global function for setting an onRequest hook\n *\n * @param {function} callback for request modifiction\n */\n\n\nVhs.xhr.onRequest = function (callback) {\n addOnRequestHook(Vhs.xhr, callback);\n};\n/**\n * A global function for setting an onResponse hook\n *\n * @param {callback} callback for response data retrieval\n */\n\n\nVhs.xhr.onResponse = function (callback) {\n addOnResponseHook(Vhs.xhr, callback);\n};\n/**\n * Deletes a global onRequest callback if it exists\n *\n * @param {function} callback to delete from the global set\n */\n\n\nVhs.xhr.offRequest = function (callback) {\n removeOnRequestHook(Vhs.xhr, callback);\n};\n/**\n * Deletes a global onResponse callback if it exists\n *\n * @param {function} callback to delete from the global set\n */\n\n\nVhs.xhr.offResponse = function (callback) {\n removeOnResponseHook(Vhs.xhr, callback);\n};\n\nconst Component = videojs.getComponent('Component');\n/**\n * The Vhs Handler object, where we orchestrate all of the parts\n * of VHS to interact with video.js\n *\n * @class VhsHandler\n * @extends videojs.Component\n * @param {Object} source the soruce object\n * @param {Tech} tech the parent tech object\n * @param {Object} options optional and required options\n */\n\nclass VhsHandler extends Component {\n constructor(source, tech, options) {\n super(tech, options.vhs); // if a tech level `initialBandwidth` option was passed\n // use that over the VHS level `bandwidth` option\n\n if (typeof options.initialBandwidth === 'number') {\n this.options_.bandwidth = options.initialBandwidth;\n }\n\n this.logger_ = logger('VhsHandler'); // we need access to the player in some cases,\n // so, get it from Video.js via the `playerId`\n\n if (tech.options_ && tech.options_.playerId) {\n const _player = videojs.getPlayer(tech.options_.playerId);\n\n this.player_ = _player;\n }\n\n this.tech_ = tech;\n this.source_ = source;\n this.stats = {};\n this.ignoreNextSeekingEvent_ = false;\n this.setOptions_();\n\n if (this.options_.overrideNative && tech.overrideNativeAudioTracks && tech.overrideNativeVideoTracks) {\n tech.overrideNativeAudioTracks(true);\n tech.overrideNativeVideoTracks(true);\n } else if (this.options_.overrideNative && (tech.featuresNativeVideoTracks || tech.featuresNativeAudioTracks)) {\n // overriding native VHS only works if audio tracks have been emulated\n // error early if we're misconfigured\n throw new Error('Overriding native VHS requires emulated tracks. ' + 'See https://git.io/vMpjB');\n } // listen for fullscreenchange events for this player so that we\n // can adjust our quality selection quickly\n\n\n this.on(document, ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'], event => {\n const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;\n\n if (fullscreenElement && fullscreenElement.contains(this.tech_.el())) {\n this.playlistController_.fastQualityChange_();\n } else {\n // When leaving fullscreen, since the in page pixel dimensions should be smaller\n // than full screen, see if there should be a rendition switch down to preserve\n // bandwidth.\n this.playlistController_.checkABR_();\n }\n });\n this.on(this.tech_, 'seeking', function () {\n if (this.ignoreNextSeekingEvent_) {\n this.ignoreNextSeekingEvent_ = false;\n return;\n }\n\n this.setCurrentTime(this.tech_.currentTime());\n });\n this.on(this.tech_, 'error', function () {\n // verify that the error was real and we are loaded\n // enough to have pc loaded.\n if (this.tech_.error() && this.playlistController_) {\n this.playlistController_.pauseLoading();\n }\n });\n this.on(this.tech_, 'play', this.play);\n }\n /**\n * Set VHS options based on options from configuration, as well as partial\n * options to be passed at a later time.\n *\n * @param {Object} options A partial chunk of config options\n */\n\n\n setOptions_(options = {}) {\n this.options_ = merge(this.options_, options); // defaults\n\n this.options_.withCredentials = this.options_.withCredentials || false;\n this.options_.limitRenditionByPlayerDimensions = this.options_.limitRenditionByPlayerDimensions === false ? false : true;\n this.options_.useDevicePixelRatio = this.options_.useDevicePixelRatio || false;\n this.options_.useBandwidthFromLocalStorage = typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? this.source_.useBandwidthFromLocalStorage : this.options_.useBandwidthFromLocalStorage || false;\n this.options_.useForcedSubtitles = this.options_.useForcedSubtitles || false;\n this.options_.useNetworkInformationApi = this.options_.useNetworkInformationApi || false;\n this.options_.useDtsForTimestampOffset = this.options_.useDtsForTimestampOffset || false;\n this.options_.customTagParsers = this.options_.customTagParsers || [];\n this.options_.customTagMappers = this.options_.customTagMappers || [];\n this.options_.cacheEncryptionKeys = this.options_.cacheEncryptionKeys || false;\n this.options_.llhls = this.options_.llhls === false ? false : true;\n this.options_.bufferBasedABR = this.options_.bufferBasedABR || false;\n\n if (typeof this.options_.playlistExclusionDuration !== 'number') {\n this.options_.playlistExclusionDuration = 60;\n }\n\n if (typeof this.options_.bandwidth !== 'number') {\n if (this.options_.useBandwidthFromLocalStorage) {\n const storedObject = getVhsLocalStorage();\n\n if (storedObject && storedObject.bandwidth) {\n this.options_.bandwidth = storedObject.bandwidth;\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-bandwidth-from-local-storage'\n });\n }\n\n if (storedObject && storedObject.throughput) {\n this.options_.throughput = storedObject.throughput;\n this.tech_.trigger({\n type: 'usage',\n name: 'vhs-throughput-from-local-storage'\n });\n }\n }\n } // if bandwidth was not set by options or pulled from local storage, start playlist\n // selection at a reasonable bandwidth\n\n\n if (typeof this.options_.bandwidth !== 'number') {\n this.options_.bandwidth = Config.INITIAL_BANDWIDTH;\n } // If the bandwidth number is unchanged from the initial setting\n // then this takes precedence over the enableLowInitialPlaylist option\n\n\n this.options_.enableLowInitialPlaylist = this.options_.enableLowInitialPlaylist && this.options_.bandwidth === Config.INITIAL_BANDWIDTH; // grab options passed to player.src\n\n ['withCredentials', 'useDevicePixelRatio', 'customPixelRatio', 'limitRenditionByPlayerDimensions', 'bandwidth', 'customTagParsers', 'customTagMappers', 'cacheEncryptionKeys', 'playlistSelector', 'initialPlaylistSelector', 'bufferBasedABR', 'liveRangeSafeTimeDelta', 'llhls', 'useForcedSubtitles', 'useNetworkInformationApi', 'useDtsForTimestampOffset', 'exactManifestTimings', 'leastPixelDiffSelector'].forEach(option => {\n if (typeof this.source_[option] !== 'undefined') {\n this.options_[option] = this.source_[option];\n }\n });\n this.limitRenditionByPlayerDimensions = this.options_.limitRenditionByPlayerDimensions;\n this.useDevicePixelRatio = this.options_.useDevicePixelRatio;\n const customPixelRatio = this.options_.customPixelRatio; // Ensure the custom pixel ratio is a number greater than or equal to 0\n\n if (typeof customPixelRatio === 'number' && customPixelRatio >= 0) {\n this.customPixelRatio = customPixelRatio;\n }\n } // alias for public method to set options\n\n\n setOptions(options = {}) {\n this.setOptions_(options);\n }\n /**\n * called when player.src gets called, handle a new source\n *\n * @param {Object} src the source object to handle\n */\n\n\n src(src, type) {\n // do nothing if the src is falsey\n if (!src) {\n return;\n }\n\n this.setOptions_(); // add main playlist controller options\n\n this.options_.src = expandDataUri(this.source_.src);\n this.options_.tech = this.tech_;\n this.options_.externVhs = Vhs;\n this.options_.sourceType = simpleTypeFromSourceType(type); // Whenever we seek internally, we should update the tech\n\n this.options_.seekTo = time => {\n this.tech_.setCurrentTime(time);\n }; // pass player to allow for player level eventing on construction.\n\n\n this.options_.player_ = this.player_;\n this.playlistController_ = new PlaylistController(this.options_);\n const playbackWatcherOptions = merge({\n liveRangeSafeTimeDelta: SAFE_TIME_DELTA\n }, this.options_, {\n seekable: () => this.seekable(),\n media: () => this.playlistController_.media(),\n playlistController: this.playlistController_\n });\n this.playbackWatcher_ = new PlaybackWatcher(playbackWatcherOptions);\n this.attachStreamingEventListeners_();\n this.playlistController_.on('error', () => {\n const player = videojs.players[this.tech_.options_.playerId];\n let error = this.playlistController_.error;\n\n if (typeof error === 'object' && !error.code) {\n error.code = 3;\n } else if (typeof error === 'string') {\n error = {\n message: error,\n code: 3\n };\n }\n\n player.error(error);\n });\n const defaultSelector = this.options_.bufferBasedABR ? Vhs.movingAverageBandwidthSelector(0.55) : Vhs.STANDARD_PLAYLIST_SELECTOR; // `this` in selectPlaylist should be the VhsHandler for backwards\n // compatibility with < v2\n\n this.playlistController_.selectPlaylist = this.selectPlaylist ? this.selectPlaylist.bind(this) : defaultSelector.bind(this);\n this.playlistController_.selectInitialPlaylist = Vhs.INITIAL_PLAYLIST_SELECTOR.bind(this); // re-expose some internal objects for backwards compatibility with < v2\n\n this.playlists = this.playlistController_.mainPlaylistLoader_;\n this.mediaSource = this.playlistController_.mediaSource; // Proxy assignment of some properties to the main playlist\n // controller. Using a custom property for backwards compatibility\n // with < v2\n\n Object.defineProperties(this, {\n selectPlaylist: {\n get() {\n return this.playlistController_.selectPlaylist;\n },\n\n set(selectPlaylist) {\n this.playlistController_.selectPlaylist = selectPlaylist.bind(this);\n }\n\n },\n throughput: {\n get() {\n return this.playlistController_.mainSegmentLoader_.throughput.rate;\n },\n\n set(throughput) {\n this.playlistController_.mainSegmentLoader_.throughput.rate = throughput; // By setting `count` to 1 the throughput value becomes the starting value\n // for the cumulative average\n\n this.playlistController_.mainSegmentLoader_.throughput.count = 1;\n }\n\n },\n bandwidth: {\n get() {\n let playerBandwidthEst = this.playlistController_.mainSegmentLoader_.bandwidth;\n const networkInformation = window$1.navigator.connection || window$1.navigator.mozConnection || window$1.navigator.webkitConnection;\n const tenMbpsAsBitsPerSecond = 10e6;\n\n if (this.options_.useNetworkInformationApi && networkInformation) {\n // downlink returns Mbps\n // https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink\n const networkInfoBandwidthEstBitsPerSec = networkInformation.downlink * 1000 * 1000; // downlink maxes out at 10 Mbps. In the event that both networkInformationApi and the player\n // estimate a bandwidth greater than 10 Mbps, use the larger of the two estimates to ensure that\n // high quality streams are not filtered out.\n\n if (networkInfoBandwidthEstBitsPerSec >= tenMbpsAsBitsPerSecond && playerBandwidthEst >= tenMbpsAsBitsPerSecond) {\n playerBandwidthEst = Math.max(playerBandwidthEst, networkInfoBandwidthEstBitsPerSec);\n } else {\n playerBandwidthEst = networkInfoBandwidthEstBitsPerSec;\n }\n }\n\n return playerBandwidthEst;\n },\n\n set(bandwidth) {\n this.playlistController_.mainSegmentLoader_.bandwidth = bandwidth; // setting the bandwidth manually resets the throughput counter\n // `count` is set to zero that current value of `rate` isn't included\n // in the cumulative average\n\n this.playlistController_.mainSegmentLoader_.throughput = {\n rate: 0,\n count: 0\n };\n }\n\n },\n\n /**\n * `systemBandwidth` is a combination of two serial processes bit-rates. The first\n * is the network bitrate provided by `bandwidth` and the second is the bitrate of\n * the entire process after that - decryption, transmuxing, and appending - provided\n * by `throughput`.\n *\n * Since the two process are serial, the overall system bandwidth is given by:\n * sysBandwidth = 1 / (1 / bandwidth + 1 / throughput)\n */\n systemBandwidth: {\n get() {\n const invBandwidth = 1 / (this.bandwidth || 1);\n let invThroughput;\n\n if (this.throughput > 0) {\n invThroughput = 1 / this.throughput;\n } else {\n invThroughput = 0;\n }\n\n const systemBitrate = Math.floor(1 / (invBandwidth + invThroughput));\n return systemBitrate;\n },\n\n set() {\n videojs.log.error('The \"systemBandwidth\" property is read-only');\n }\n\n }\n });\n\n if (this.options_.bandwidth) {\n this.bandwidth = this.options_.bandwidth;\n }\n\n if (this.options_.throughput) {\n this.throughput = this.options_.throughput;\n }\n\n Object.defineProperties(this.stats, {\n bandwidth: {\n get: () => this.bandwidth || 0,\n enumerable: true\n },\n mediaRequests: {\n get: () => this.playlistController_.mediaRequests_() || 0,\n enumerable: true\n },\n mediaRequestsAborted: {\n get: () => this.playlistController_.mediaRequestsAborted_() || 0,\n enumerable: true\n },\n mediaRequestsTimedout: {\n get: () => this.playlistController_.mediaRequestsTimedout_() || 0,\n enumerable: true\n },\n mediaRequestsErrored: {\n get: () => this.playlistController_.mediaRequestsErrored_() || 0,\n enumerable: true\n },\n mediaTransferDuration: {\n get: () => this.playlistController_.mediaTransferDuration_() || 0,\n enumerable: true\n },\n mediaBytesTransferred: {\n get: () => this.playlistController_.mediaBytesTransferred_() || 0,\n enumerable: true\n },\n mediaSecondsLoaded: {\n get: () => this.playlistController_.mediaSecondsLoaded_() || 0,\n enumerable: true\n },\n mediaAppends: {\n get: () => this.playlistController_.mediaAppends_() || 0,\n enumerable: true\n },\n mainAppendsToLoadedData: {\n get: () => this.playlistController_.mainAppendsToLoadedData_() || 0,\n enumerable: true\n },\n audioAppendsToLoadedData: {\n get: () => this.playlistController_.audioAppendsToLoadedData_() || 0,\n enumerable: true\n },\n appendsToLoadedData: {\n get: () => this.playlistController_.appendsToLoadedData_() || 0,\n enumerable: true\n },\n timeToLoadedData: {\n get: () => this.playlistController_.timeToLoadedData_() || 0,\n enumerable: true\n },\n buffered: {\n get: () => timeRangesToArray(this.tech_.buffered()),\n enumerable: true\n },\n currentTime: {\n get: () => this.tech_.currentTime(),\n enumerable: true\n },\n currentSource: {\n get: () => this.tech_.currentSource_,\n enumerable: true\n },\n currentTech: {\n get: () => this.tech_.name_,\n enumerable: true\n },\n duration: {\n get: () => this.tech_.duration(),\n enumerable: true\n },\n main: {\n get: () => this.playlists.main,\n enumerable: true\n },\n playerDimensions: {\n get: () => this.tech_.currentDimensions(),\n enumerable: true\n },\n seekable: {\n get: () => timeRangesToArray(this.tech_.seekable()),\n enumerable: true\n },\n timestamp: {\n get: () => Date.now(),\n enumerable: true\n },\n videoPlaybackQuality: {\n get: () => this.tech_.getVideoPlaybackQuality(),\n enumerable: true\n }\n });\n this.tech_.one('canplay', this.playlistController_.setupFirstPlay.bind(this.playlistController_));\n this.tech_.on('bandwidthupdate', () => {\n if (this.options_.useBandwidthFromLocalStorage) {\n updateVhsLocalStorage({\n bandwidth: this.bandwidth,\n throughput: Math.round(this.throughput)\n });\n }\n });\n this.playlistController_.on('selectedinitialmedia', () => {\n // Add the manual rendition mix-in to VhsHandler\n renditionSelectionMixin(this);\n });\n this.playlistController_.sourceUpdater_.on('createdsourcebuffers', () => {\n this.setupEme_();\n }); // the bandwidth of the primary segment loader is our best\n // estimate of overall bandwidth\n\n this.on(this.playlistController_, 'progress', function () {\n this.tech_.trigger('progress');\n }); // In the live case, we need to ignore the very first `seeking` event since\n // that will be the result of the seek-to-live behavior\n\n this.on(this.playlistController_, 'firstplay', function () {\n this.ignoreNextSeekingEvent_ = true;\n });\n this.setupQualityLevels_(); // do nothing if the tech has been disposed already\n // this can occur if someone sets the src in player.ready(), for instance\n\n if (!this.tech_.el()) {\n return;\n }\n\n this.mediaSourceUrl_ = window$1.URL.createObjectURL(this.playlistController_.mediaSource); // If we are playing HLS with MSE in Safari, add source elements for both the blob and manifest URLs.\n // The latter will enable Airplay playback on receiver devices.\n\n if ((videojs.browser.IS_ANY_SAFARI || videojs.browser.IS_IOS) && this.options_.overrideNative && this.options_.sourceType === 'hls' && typeof this.tech_.addSourceElement === 'function') {\n this.tech_.addSourceElement(this.mediaSourceUrl_);\n this.tech_.addSourceElement(this.source_.src);\n } else {\n this.tech_.src(this.mediaSourceUrl_);\n }\n }\n\n createKeySessions_() {\n const audioPlaylistLoader = this.playlistController_.mediaTypes_.AUDIO.activePlaylistLoader;\n this.logger_('waiting for EME key session creation');\n waitForKeySessionCreation({\n player: this.player_,\n sourceKeySystems: this.source_.keySystems,\n audioMedia: audioPlaylistLoader && audioPlaylistLoader.media(),\n mainPlaylists: this.playlists.main.playlists\n }).then(() => {\n this.logger_('created EME key session');\n this.playlistController_.sourceUpdater_.initializedEme();\n }).catch(err => {\n this.logger_('error while creating EME key session', err);\n this.player_.error({\n message: 'Failed to initialize media keys for EME',\n code: 3\n });\n });\n }\n\n handleWaitingForKey_() {\n // If waitingforkey is fired, it's possible that the data that's necessary to retrieve\n // the key is in the manifest. While this should've happened on initial source load, it\n // may happen again in live streams where the keys change, and the manifest info\n // reflects the update.\n //\n // Because videojs-contrib-eme compares the PSSH data we send to that of PSSH data it's\n // already requested keys for, we don't have to worry about this generating extraneous\n // requests.\n this.logger_('waitingforkey fired, attempting to create any new key sessions');\n this.createKeySessions_();\n }\n /**\n * If necessary and EME is available, sets up EME options and waits for key session\n * creation.\n *\n * This function also updates the source updater so taht it can be used, as for some\n * browsers, EME must be configured before content is appended (if appending unencrypted\n * content before encrypted content).\n */\n\n\n setupEme_() {\n const audioPlaylistLoader = this.playlistController_.mediaTypes_.AUDIO.activePlaylistLoader;\n const didSetupEmeOptions = setupEmeOptions({\n player: this.player_,\n sourceKeySystems: this.source_.keySystems,\n media: this.playlists.media(),\n audioMedia: audioPlaylistLoader && audioPlaylistLoader.media()\n });\n this.player_.tech_.on('keystatuschange', e => {\n this.playlistController_.updatePlaylistByKeyStatus(e.keyId, e.status);\n });\n this.handleWaitingForKey_ = this.handleWaitingForKey_.bind(this);\n this.player_.tech_.on('waitingforkey', this.handleWaitingForKey_);\n\n if (!didSetupEmeOptions) {\n // If EME options were not set up, we've done all we could to initialize EME.\n this.playlistController_.sourceUpdater_.initializedEme();\n return;\n }\n\n this.createKeySessions_();\n }\n /**\n * Initializes the quality levels and sets listeners to update them.\n *\n * @method setupQualityLevels_\n * @private\n */\n\n\n setupQualityLevels_() {\n const player = videojs.players[this.tech_.options_.playerId]; // if there isn't a player or there isn't a qualityLevels plugin\n // or qualityLevels_ listeners have already been setup, do nothing.\n\n if (!player || !player.qualityLevels || this.qualityLevels_) {\n return;\n }\n\n this.qualityLevels_ = player.qualityLevels();\n this.playlistController_.on('selectedinitialmedia', () => {\n handleVhsLoadedMetadata(this.qualityLevels_, this);\n });\n this.playlists.on('mediachange', () => {\n handleVhsMediaChange(this.qualityLevels_, this.playlists);\n });\n }\n /**\n * return the version\n */\n\n\n static version() {\n return {\n '@videojs/http-streaming': version$4,\n 'mux.js': version$3,\n 'mpd-parser': version$2,\n 'm3u8-parser': version$1,\n 'aes-decrypter': version\n };\n }\n /**\n * return the version\n */\n\n\n version() {\n return this.constructor.version();\n }\n\n canChangeType() {\n return SourceUpdater.canChangeType();\n }\n /**\n * Begin playing the video.\n */\n\n\n play() {\n this.playlistController_.play();\n }\n /**\n * a wrapper around the function in PlaylistController\n */\n\n\n setCurrentTime(currentTime) {\n this.playlistController_.setCurrentTime(currentTime);\n }\n /**\n * a wrapper around the function in PlaylistController\n */\n\n\n duration() {\n return this.playlistController_.duration();\n }\n /**\n * a wrapper around the function in PlaylistController\n */\n\n\n seekable() {\n return this.playlistController_.seekable();\n }\n /**\n * Abort all outstanding work and cleanup.\n */\n\n\n dispose() {\n if (this.playbackWatcher_) {\n this.playbackWatcher_.dispose();\n }\n\n if (this.playlistController_) {\n this.playlistController_.dispose();\n }\n\n if (this.qualityLevels_) {\n this.qualityLevels_.dispose();\n }\n\n if (this.tech_ && this.tech_.vhs) {\n delete this.tech_.vhs;\n }\n\n if (this.mediaSourceUrl_ && window$1.URL.revokeObjectURL) {\n window$1.URL.revokeObjectURL(this.mediaSourceUrl_);\n this.mediaSourceUrl_ = null;\n }\n\n if (this.tech_) {\n this.tech_.off('waitingforkey', this.handleWaitingForKey_);\n }\n\n super.dispose();\n }\n\n convertToProgramTime(time, callback) {\n return getProgramTime({\n playlist: this.playlistController_.media(),\n time,\n callback\n });\n } // the player must be playing before calling this\n\n\n seekToProgramTime(programTime, callback, pauseAfterSeek = true, retryCount = 2) {\n return seekToProgramTime({\n programTime,\n playlist: this.playlistController_.media(),\n retryCount,\n pauseAfterSeek,\n seekTo: this.options_.seekTo,\n tech: this.options_.tech,\n callback\n });\n }\n /**\n * Adds the onRequest, onResponse, offRequest and offResponse functions\n * to the VhsHandler xhr Object.\n */\n\n\n setupXhrHooks_() {\n /**\n * A player function for setting an onRequest hook\n *\n * @param {function} callback for request modifiction\n */\n this.xhr.onRequest = callback => {\n addOnRequestHook(this.xhr, callback);\n };\n /**\n * A player function for setting an onResponse hook\n *\n * @param {callback} callback for response data retrieval\n */\n\n\n this.xhr.onResponse = callback => {\n addOnResponseHook(this.xhr, callback);\n };\n /**\n * Deletes a player onRequest callback if it exists\n *\n * @param {function} callback to delete from the player set\n */\n\n\n this.xhr.offRequest = callback => {\n removeOnRequestHook(this.xhr, callback);\n };\n /**\n * Deletes a player onResponse callback if it exists\n *\n * @param {function} callback to delete from the player set\n */\n\n\n this.xhr.offResponse = callback => {\n removeOnResponseHook(this.xhr, callback);\n }; // Trigger an event on the player to notify the user that vhs is ready to set xhr hooks.\n // This allows hooks to be set before the source is set to vhs when handleSource is called.\n\n\n this.player_.trigger('xhr-hooks-ready');\n }\n\n attachStreamingEventListeners_() {\n const playlistControllerEvents = ['seekablerangeschanged', 'bufferedrangeschanged', 'contentsteeringloadstart', 'contentsteeringloadcomplete', 'contentsteeringparsed'];\n const playbackWatcher = ['gapjumped', 'playedrangeschanged']; // re-emit streaming events and payloads on the player.\n\n playlistControllerEvents.forEach(eventName => {\n this.playlistController_.on(eventName, metadata => {\n this.player_.trigger(_extends({}, metadata));\n });\n });\n playbackWatcher.forEach(eventName => {\n this.playbackWatcher_.on(eventName, metadata => {\n this.player_.trigger(_extends({}, metadata));\n });\n });\n }\n\n}\n/**\n * The Source Handler object, which informs video.js what additional\n * MIME types are supported and sets up playback. It is registered\n * automatically to the appropriate tech based on the capabilities of\n * the browser it is running in. It is not necessary to use or modify\n * this object in normal usage.\n */\n\n\nconst VhsSourceHandler = {\n name: 'videojs-http-streaming',\n VERSION: version$4,\n\n canHandleSource(srcObj, options = {}) {\n const localOptions = merge(videojs.options, options); // If not opting to experimentalUseMMS, and playback is only supported with MediaSource, cannot handle source\n\n if (!localOptions.vhs.experimentalUseMMS && !browserSupportsCodec('avc1.4d400d,mp4a.40.2', false)) {\n return false;\n }\n\n return VhsSourceHandler.canPlayType(srcObj.type, localOptions);\n },\n\n handleSource(source, tech, options = {}) {\n const localOptions = merge(videojs.options, options);\n tech.vhs = new VhsHandler(source, tech, localOptions);\n tech.vhs.xhr = xhrFactory();\n tech.vhs.setupXhrHooks_();\n tech.vhs.src(source.src, source.type);\n return tech.vhs;\n },\n\n canPlayType(type, options) {\n const simpleType = simpleTypeFromSourceType(type);\n\n if (!simpleType) {\n return '';\n }\n\n const overrideNative = VhsSourceHandler.getOverrideNative(options);\n const supportsTypeNatively = Vhs.supportsTypeNatively(simpleType);\n const canUseMsePlayback = !supportsTypeNatively || overrideNative;\n return canUseMsePlayback ? 'maybe' : '';\n },\n\n getOverrideNative(options = {}) {\n const {\n vhs = {}\n } = options;\n const defaultOverrideNative = !(videojs.browser.IS_ANY_SAFARI || videojs.browser.IS_IOS);\n const {\n overrideNative = defaultOverrideNative\n } = vhs;\n return overrideNative;\n }\n\n};\n/**\n * Check to see if either the native MediaSource or ManagedMediaSource\n * objectx exist and support an MP4 container with both H.264 video\n * and AAC-LC audio.\n *\n * @return {boolean} if native media sources are supported\n */\n\nconst supportsNativeMediaSources = () => {\n return browserSupportsCodec('avc1.4d400d,mp4a.40.2', true);\n}; // register source handlers with the appropriate techs\n\n\nif (supportsNativeMediaSources()) {\n videojs.getTech('Html5').registerSourceHandler(VhsSourceHandler, 0);\n}\n\nvideojs.VhsHandler = VhsHandler;\nvideojs.VhsSourceHandler = VhsSourceHandler;\nvideojs.Vhs = Vhs;\n\nif (!videojs.use) {\n videojs.registerComponent('Vhs', Vhs);\n}\n\nvideojs.options.vhs = videojs.options.vhs || {};\n\nif (!videojs.getPlugin || !videojs.getPlugin('reloadSourceOnError')) {\n videojs.registerPlugin('reloadSourceOnError', reloadSourceOnError);\n}\n\nexport { LOCAL_STORAGE_KEY, Vhs, VhsHandler, VhsSourceHandler, emeKeySystems, expandDataUri, getAllPsshKeySystemsOptions, setupEmeOptions, waitForKeySessionCreation };\n"],"sourceRoot":""}