diff --git a/src/adts/adts-demuxer.ts b/src/adts/adts-demuxer.ts index d39427f..96423e2 100644 --- a/src/adts/adts-demuxer.ts +++ b/src/adts/adts-demuxer.ts @@ -23,6 +23,7 @@ import { AsyncMutex, binarySearchExact, binarySearchLessOrEqual, + isThenable, UNDETERMINED_LANGUAGE, } from '../misc'; import { EncodedPacket, PLACEHOLDER_DATA } from '../packet'; @@ -84,7 +85,7 @@ export class AdtsDemuxer extends Demuxer { // Skip all ID3v2 tags at the start of the file while (true) { let slice = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { this.lastSampleLoaded = true; @@ -105,7 +106,7 @@ export class AdtsDemuxer extends Demuxer { MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { this.lastSampleLoaded = true; return; @@ -167,7 +168,7 @@ export class AdtsDemuxer extends Demuxer { while (true) { let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; if (!headerSlice) break; const id3V2Header = readId3V2Header(headerSlice); @@ -176,7 +177,7 @@ export class AdtsDemuxer extends Demuxer { } let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) contentSlice = await contentSlice; + if (isThenable(contentSlice)) contentSlice = await contentSlice; if (!contentSlice) break; parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); @@ -306,7 +307,7 @@ class AdtsAudioTrackBacking implements InputAudioTrackBacking { data = PLACEHOLDER_DATA; } else { let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; // Data didn't fit into the rest of the file diff --git a/src/aes.ts b/src/aes.ts index 4a54618..50bf2b2 100644 --- a/src/aes.ts +++ b/src/aes.ts @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { assert, MaybePromise } from './misc'; +import { assert, isThenable, MaybePromise } from './misc'; import { readBytes, Reader } from './reader'; // Inspired in part by https://github.com/halloweeks/AES-128-CBC/blob/main/AES_128_CBC.h @@ -258,7 +258,7 @@ export const createAes128CbcDecryptStream = ( const requestedLength = CHUNK_SIZE + BLOCK_SIZE; let nextSlice = reader.requestSliceRange(pos, 0, requestedLength); - if (nextSlice instanceof Promise) nextSlice = await nextSlice; + if (isThenable(nextSlice)) nextSlice = await nextSlice; if (!nextSlice || nextSlice.length === 0) { // Due to padding, this should never happen throw new Error('Invalid ciphertext.'); diff --git a/src/flac/flac-demuxer.ts b/src/flac/flac-demuxer.ts index 2334ce5..7a581d0 100644 --- a/src/flac/flac-demuxer.ts +++ b/src/flac/flac-demuxer.ts @@ -15,6 +15,7 @@ import { assert, AsyncMutex, binarySearchLessOrEqual, + isThenable, textDecoder, UNDETERMINED_LANGUAGE, } from '../misc'; @@ -108,7 +109,7 @@ export class FlacDemuxer extends Demuxer { let currentPos = 0; while (true) { let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; if (!headerSlice) { this.lastSampleLoaded = true; @@ -121,7 +122,7 @@ export class FlacDemuxer extends Demuxer { } let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) contentSlice = await contentSlice; + if (isThenable(contentSlice)) contentSlice = await contentSlice; assert(contentSlice); parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); @@ -136,7 +137,7 @@ export class FlacDemuxer extends Demuxer { || currentPos < this.reader.fileSize ) { let sizeSlice = this.reader.requestSlice(currentPos, 4); - if (sizeSlice instanceof Promise) sizeSlice = await sizeSlice; + if (isThenable(sizeSlice)) sizeSlice = await sizeSlice; currentPos += 4; if (sizeSlice === null) { @@ -160,7 +161,7 @@ export class FlacDemuxer extends Demuxer { currentPos, size, ); - if (streamInfoBlock instanceof Promise) streamInfoBlock = await streamInfoBlock; + if (isThenable(streamInfoBlock)) streamInfoBlock = await streamInfoBlock; assert(streamInfoBlock); if (streamInfoBlock === null) { @@ -219,7 +220,7 @@ export class FlacDemuxer extends Demuxer { currentPos, size, ); - if (vorbisCommentBlock instanceof Promise) vorbisCommentBlock = await vorbisCommentBlock; + if (isThenable(vorbisCommentBlock)) vorbisCommentBlock = await vorbisCommentBlock; assert(vorbisCommentBlock); @@ -237,7 +238,7 @@ export class FlacDemuxer extends Demuxer { currentPos, size, ); - if (pictureBlock instanceof Promise) pictureBlock = await pictureBlock; + if (isThenable(pictureBlock)) pictureBlock = await pictureBlock; assert(pictureBlock); const pictureType = readU32Be(pictureBlock); @@ -775,7 +776,7 @@ class FlacAudioTrackBacking implements InputAudioTrackBacking { rawSample.byteOffset, rawSample.byteSize, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; // Data didn't fit into the rest of the file diff --git a/src/input-format.ts b/src/input-format.ts index b61adeb..5ce740e 100644 --- a/src/input-format.ts +++ b/src/input-format.ts @@ -36,7 +36,7 @@ import { TS_PACKET_SIZE } from './mpeg-ts/mpeg-ts-misc'; import { HlsDemuxer } from './hls/hls-demuxer'; import { HLS_MIME_TYPE } from './hls/hls-misc'; import { PathedSource } from './source'; -import { MaybePromise } from './misc'; +import { isThenable, MaybePromise } from './misc'; /** * Base class representing an input media file format. @@ -75,7 +75,7 @@ export abstract class IsobmffInputFormat extends InputFormat { /** @internal */ protected async _getMajorBrand(input: Input) { let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return null; slice.skip(4); @@ -117,7 +117,7 @@ export class Mp4InputFormat extends IsobmffInputFormat { } let slice = input._reader.requestSlice(4, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const fourCc = readAscii(slice, 4); @@ -169,7 +169,7 @@ export class MatroskaInputFormat extends InputFormat { /** @internal */ protected async isSupportedEBMLOfDocType(input: Input, desiredDocType: string) { let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; if (!headerSlice) return false; const varIntSize = readVarIntSize(headerSlice); @@ -192,7 +192,7 @@ export class MatroskaInputFormat extends InputFormat { } let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); - if (dataSlice instanceof Promise) dataSlice = await dataSlice; + if (isThenable(dataSlice)) dataSlice = await dataSlice; if (!dataSlice) return false; const startPos = headerSlice.filePos; @@ -295,7 +295,7 @@ export class Mp3InputFormat extends InputFormat { while (true) { let slice = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const id3V2Header = readId3V2Header(slice); @@ -315,7 +315,7 @@ export class Mp3InputFormat extends InputFormat { const xingOffset = getXingOffset(firstHeader.mpegVersionId, firstHeader.channel); let slice = input._reader.requestSlice(firstResult.startPos + xingOffset, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const word = readU32Be(slice); @@ -376,7 +376,7 @@ export class WaveInputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const riffType = readAscii(slice, 4); @@ -416,7 +416,7 @@ export class OggInputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; return readAscii(slice, 4) === 'OggS'; @@ -451,7 +451,7 @@ export class FlacInputFormat extends InputFormat { // There might be ID3v2 headers at the start, skip 'em while (true) { let slice = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const id3V2Header = readId3V2Header(slice); @@ -463,7 +463,7 @@ export class FlacInputFormat extends InputFormat { } let slice = input._reader.requestSlice(currentPos, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; return readAscii(slice, 4) === 'fLaC'; @@ -498,7 +498,7 @@ export class AdtsInputFormat extends InputFormat { while (true) { let slice = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const id3V2Header = readId3V2Header(slice); @@ -514,7 +514,7 @@ export class AdtsInputFormat extends InputFormat { MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const firstHeader = readAdtsFrameHeader(slice); @@ -529,7 +529,7 @@ export class AdtsInputFormat extends InputFormat { MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const secondHeader = readAdtsFrameHeader(slice); @@ -573,7 +573,7 @@ export class MpegTsInputFormat extends InputFormat { async _canReadInput(input: Input) { const lengthToCheck = TS_PACKET_SIZE + 16 + 1; let slice = input._reader.requestSlice(0, lengthToCheck); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const bytes = readBytes(slice, lengthToCheck); @@ -618,7 +618,7 @@ export class HlsInputFormat extends InputFormat { /** @internal */ async _canReadInput(input: Input) { let slice = input._reader.requestSlice(0, 7); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return false; const isM3u8 = readAscii(slice, 7) === '#EXTM3U'; diff --git a/src/input-track.ts b/src/input-track.ts index 2a6400d..f1b6a16 100644 --- a/src/input-track.ts +++ b/src/input-track.ts @@ -12,7 +12,7 @@ import { customAudioDecoders, customVideoDecoders } from './custom-coder'; import { Input } from './input'; import { Logging } from './logging'; import { EncodedPacketSink, PacketRetrievalOptions } from './media-sink'; -import { assert, MaybePromise, Rational, Rotation, roundToDivisor, simplifyRational } from './misc'; +import { assert, isThenable, MaybePromise, Rational, Rotation, roundToDivisor, simplifyRational } from './misc'; import { TrackType } from './output'; import { EncodedPacket, PacketType } from './packet'; import { TrackDisposition } from './metadata'; @@ -528,7 +528,7 @@ export abstract class InputTrack { } const requireSync = (value: MaybePromise, getterName: string, asyncName: string): T => { - if (value instanceof Promise) { + if (isThenable(value)) { throw new Error( `'${getterName}' is deprecated and not available synchronously for this track. Use the preferred` + ` '${asyncName}()' instead.`, @@ -554,7 +554,7 @@ const toValidatedPredicate = ( }; const result = predicate(track); - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(handle); } return handle(result); @@ -1225,7 +1225,7 @@ export const toValidatedInputTrackQuery = ( }; const result = query.filter!(track); - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(handle); } else { return handle(result); @@ -1248,7 +1248,7 @@ export const toValidatedInputTrackQuery = ( }; const result = query.sortBy!(track); - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(handle); } else { return handle(result); @@ -1274,7 +1274,7 @@ export const mergeInputTrackQueries = ( return queryB?.filter?.(track) ?? true; }; - if (resultA instanceof Promise) { + if (isThenable(resultA)) { return resultA.then(handleResultA); } else { return handleResultA(resultA); @@ -1294,7 +1294,7 @@ export const mergeInputTrackQueries = ( ]; }; - if (resultA instanceof Promise || resultB instanceof Promise) { + if (isThenable(resultA) || isThenable(resultB)) { return Promise.all([resultA, resultB]).then(([resultA, resultB]) => { return join(resultA, resultB); }); @@ -1313,7 +1313,7 @@ export const queryInputTracks = async ( let matched = tracks; if (query?.filter) { const filterMatches = tracks.map(t => query.filter!(t)); - const hasAsyncFilter = filterMatches.some(x => x instanceof Promise); + const hasAsyncFilter = filterMatches.some(x => isThenable(x)); if (hasAsyncFilter) { // eslint-disable-next-line @typescript-eslint/await-thenable const resolvedFilterMatches = await Promise.all(filterMatches); @@ -1328,7 +1328,7 @@ export const queryInputTracks = async ( } const sortValues = matched.map(t => query.sortBy!(t)); - const hasAsyncSort = sortValues.some(x => x instanceof Promise); + const hasAsyncSort = sortValues.some(x => isThenable(x)); const resolvedSortValues = hasAsyncSort // eslint-disable-next-line @typescript-eslint/await-thenable ? await Promise.all(sortValues) diff --git a/src/isobmff/isobmff-demuxer.ts b/src/isobmff/isobmff-demuxer.ts index ddaaafa..2f9ba57 100644 --- a/src/isobmff/isobmff-demuxer.ts +++ b/src/isobmff/isobmff-demuxer.ts @@ -58,6 +58,7 @@ import { COLOR_PRIMARIES_MAP_INVERSE, findLastIndex, isIso639Dash2LanguageCode, + isThenable, last, MATRIX_COEFFICIENTS_MAP_INVERSE, normalizeRotation, @@ -364,7 +365,7 @@ export class IsobmffDemuxer extends Demuxer { while (true) { let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const startPos = currentPos; @@ -380,7 +381,7 @@ export class IsobmffDemuxer extends Demuxer { // Found moov, load it let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); - if (moovSlice instanceof Promise) moovSlice = await moovSlice; + if (isThenable(moovSlice)) moovSlice = await moovSlice; if (!moovSlice) break; this.moovSlice = moovSlice; @@ -431,7 +432,7 @@ export class IsobmffDemuxer extends Demuxer { // The last 4 bytes may contain the size of the mfra box at the end of the file let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); - if (lastWordSlice instanceof Promise) lastWordSlice = await lastWordSlice; + if (isThenable(lastWordSlice)) lastWordSlice = await lastWordSlice; assert(lastWordSlice); const lastWord = readU32Be(lastWordSlice); @@ -443,7 +444,7 @@ export class IsobmffDemuxer extends Demuxer { MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE, ); - if (mfraHeaderSlice instanceof Promise) mfraHeaderSlice = await mfraHeaderSlice; + if (isThenable(mfraHeaderSlice)) mfraHeaderSlice = await mfraHeaderSlice; if (mfraHeaderSlice) { const boxInfo = readBoxHeader(mfraHeaderSlice); @@ -451,7 +452,7 @@ export class IsobmffDemuxer extends Demuxer { if (boxInfo && boxInfo.name === 'mfra') { // We found the mfra box, allowing for much better random access. Let's parse it. let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); - if (mfraSlice instanceof Promise) mfraSlice = await mfraSlice; + if (isThenable(mfraSlice)) mfraSlice = await mfraSlice; if (mfraSlice) { this.readContiguousBoxes(mfraSlice); @@ -678,14 +679,14 @@ export class IsobmffDemuxer extends Demuxer { } let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; assert(headerSlice); const moofBoxInfo = readBoxHeader(headerSlice); assert(moofBoxInfo?.name === 'moof'); let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); - if (entireSlice instanceof Promise) entireSlice = await entireSlice; + if (isThenable(entireSlice)) entireSlice = await entireSlice; assert(entireSlice); this.traverseBox(entireSlice); @@ -3144,7 +3145,7 @@ abstract class IsobmffTrackBacking implements InputTrackBacking { sampleInfo.sampleOffset, sampleInfo.sampleSize, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; // Data is outside } @@ -3207,7 +3208,7 @@ abstract class IsobmffTrackBacking implements InputTrackBacking { fragmentSample.byteOffset, fragmentSample.byteSize, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; // Data is outside } @@ -3321,7 +3322,7 @@ abstract class IsobmffTrackBacking implements InputTrackBacking { // Load the header let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const boxStartPos = currentPos; @@ -3748,7 +3749,7 @@ const resolveEncryptionAuxInfo = async ( } let slice = reader.requestSlice(aux.offset, totalSize); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { throw new Error('Failed to read auxiliary encryption info.'); } diff --git a/src/matroska/ebml.ts b/src/matroska/ebml.ts index 6cc5a88..6c93e16 100644 --- a/src/matroska/ebml.ts +++ b/src/matroska/ebml.ts @@ -7,7 +7,7 @@ */ import { MediaCodec } from '../codec'; -import { assert, assertNever, textDecoder, textEncoder } from '../misc'; +import { assert, assertNever, isThenable, textDecoder, textEncoder } from '../misc'; import { FileSlice, readBytes, Reader, readF32Be, readF64Be, readU8 } from '../reader'; import { Writer } from '../writer'; @@ -688,7 +688,7 @@ export const searchForNextElementId = async ( while (until === null || currentPos < until) { let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const elementHeader = readElementHeader(slice); @@ -716,7 +716,7 @@ export const resync = async (reader: Reader, startPos: number, ids: EBMLId[], un while (currentPos < until) { let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; if (slice.length < MAX_VAR_INT_SIZE) break; diff --git a/src/matroska/matroska-demuxer.ts b/src/matroska/matroska-demuxer.ts index 9fbbc3f..8f397c1 100644 --- a/src/matroska/matroska-demuxer.ts +++ b/src/matroska/matroska-demuxer.ts @@ -42,6 +42,7 @@ import { COLOR_PRIMARIES_MAP_INVERSE, findLastIndex, isIso639Dash2LanguageCode, + isThenable, last, MATRIX_COEFFICIENTS_MAP_INVERSE, normalizeRotation, @@ -334,7 +335,7 @@ export class MatroskaDemuxer extends Demuxer { // Loop over all top-level elements in the file while (true) { let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const header = readElementHeader(slice); @@ -350,7 +351,7 @@ export class MatroskaDemuxer extends Demuxer { assertDefinedSize(size); let slice = this.reader.requestSlice(dataStartPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; this.readContiguousElements(slice); @@ -433,7 +434,7 @@ export class MatroskaDemuxer extends Demuxer { while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const elementStartPos = currentPos; @@ -468,7 +469,7 @@ export class MatroskaDemuxer extends Demuxer { assertDefinedSize(size); let slice = this.reader.requestSlice(dataStartPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (slice) { this.readContiguousElements(slice); @@ -484,7 +485,7 @@ export class MatroskaDemuxer extends Demuxer { assertDefinedSize(size); let slice = this.reader.requestSlice(dataStartPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (slice) { this.readContiguousElements(slice); @@ -519,7 +520,7 @@ export class MatroskaDemuxer extends Demuxer { MIN_HEADER_SIZE, MAX_HEADER_SIZE, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) continue; const header = readElementHeader(slice); @@ -533,7 +534,7 @@ export class MatroskaDemuxer extends Demuxer { this.currentSegment[target.flag] = true; let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) dataSlice = await dataSlice; + if (isThenable(dataSlice)) dataSlice = await dataSlice; if (!dataSlice) continue; this.readContiguousElements(dataSlice); @@ -608,7 +609,7 @@ export class MatroskaDemuxer extends Demuxer { } let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; assert(headerSlice); const elementStartPos = startPos; @@ -637,7 +638,7 @@ export class MatroskaDemuxer extends Demuxer { // Load the entire cluster let dataSlice = this.reader.requestSlice(dataStartPos, size); - if (dataSlice instanceof Promise) dataSlice = await dataSlice; + if (isThenable(dataSlice)) dataSlice = await dataSlice; const cluster: Cluster = { segment, @@ -894,7 +895,7 @@ export class MatroskaDemuxer extends Demuxer { MIN_HEADER_SIZE, MAX_HEADER_SIZE, ); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) continue; const header = readElementHeader(slice); @@ -907,7 +908,7 @@ export class MatroskaDemuxer extends Demuxer { this.currentSegment = segment; let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) dataSlice = await dataSlice; + if (isThenable(dataSlice)) dataSlice = await dataSlice; if (dataSlice) { this.readContiguousElements(dataSlice); } @@ -2347,7 +2348,7 @@ abstract class MatroskaTrackBacking implements InputTrackBacking { // Load the header let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const elementStartPos = currentPos; @@ -2418,7 +2419,7 @@ abstract class MatroskaTrackBacking implements InputTrackBacking { // the first segment. let slice = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const elementId = readElementId(slice); diff --git a/src/media-source.ts b/src/media-source.ts index c724b96..8d82533 100644 --- a/src/media-source.ts +++ b/src/media-source.ts @@ -28,6 +28,7 @@ import { clamp, clearIntervalUnthrottled, floorToDivisor, + isThenable, last, missingWebCodecsClassMessage, promiseWithResolvers, @@ -426,7 +427,7 @@ class VideoEncoderWrapper { // Apply the user-defined process function, if any if (config.transform?.process) { let processed = config.transform.process(videoSample); - if (processed instanceof Promise) { + if (isThenable(processed)) { processed = await processed; } @@ -1937,7 +1938,7 @@ class AudioEncoderWrapper { if (config.transform?.process) { try { let processed = config.transform.process(audioSample); - if (processed instanceof Promise) { + if (isThenable(processed)) { processed = await processed; } diff --git a/src/misc.ts b/src/misc.ts index 3b0d98a..3a247d3 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -738,6 +738,20 @@ export const missingWebCodecsClassMessage = (className: string) => { */ export type MaybePromise = T | Promise; +const NativePromiseConstructor = /* #__PURE__ */ (async () => {})().constructor as PromiseConstructor; + +/** + * Needed to properly deal with custom Promise implementations and because this is closer to how the JS spec does it. + */ +export const isThenable = (value: MaybePromise): value is Promise => { + if (value instanceof NativePromiseConstructor || value instanceof Promise) { + return true; + } + + // Fall back to a crude duck typing check + return typeof (value as PromiseLike | null | undefined)?.then === 'function'; +}; + /** Acts like `??` except the condition is -1 and not null/undefined. */ export const coalesceIndex = (a: number, b: number) => { return a !== -1 ? a : b; diff --git a/src/mp3/mp3-demuxer.ts b/src/mp3/mp3-demuxer.ts index 48b3dd0..a89d222 100644 --- a/src/mp3/mp3-demuxer.ts +++ b/src/mp3/mp3-demuxer.ts @@ -17,6 +17,7 @@ import { AsyncMutex, binarySearchExact, binarySearchLessOrEqual, + isThenable, toDataView, UNDETERMINED_LANGUAGE, } from '../misc'; @@ -102,7 +103,7 @@ export class Mp3Demuxer extends Demuxer { // Let's skip all ID3v2 tags at the start of the file while (true) { let slice = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { this.lastSampleLoaded = true; @@ -136,7 +137,7 @@ export class Mp3Demuxer extends Demuxer { const xingOffset = getXingOffset(header.mpegVersionId, header.channel); let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (slice) { const word = readU32Be(slice); const isXing = word === XING || word === INFO; @@ -151,7 +152,7 @@ export class Mp3Demuxer extends Demuxer { if (!this.xingData) { let xingDataSlice = this.reader.requestSlice(result.startPos + xingOffset + 4, 12); - if (xingDataSlice instanceof Promise) xingDataSlice = await xingDataSlice; + if (isThenable(xingDataSlice)) xingDataSlice = await xingDataSlice; if (xingDataSlice) { const xingData = readBytes(xingDataSlice, 12); const view = toDataView(xingData); @@ -216,7 +217,7 @@ export class Mp3Demuxer extends Demuxer { while (true) { let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; if (!headerSlice) break; const id3V2Header = readId3V2Header(headerSlice); @@ -227,7 +228,7 @@ export class Mp3Demuxer extends Demuxer { id3V2HeaderFound = true; let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) contentSlice = await contentSlice; + if (isThenable(contentSlice)) contentSlice = await contentSlice; if (!contentSlice) break; parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); @@ -238,7 +239,7 @@ export class Mp3Demuxer extends Demuxer { if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { // Try reading an ID3v1 tag at the end of the file let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; assert(slice); const tag = readAscii(slice, 3); @@ -388,7 +389,7 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking { data = PLACEHOLDER_DATA; } else { let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; // Data didn't fit into the rest of the file diff --git a/src/mp3/mp3-reader.ts b/src/mp3/mp3-reader.ts index 4897dda..29c4689 100644 --- a/src/mp3/mp3-reader.ts +++ b/src/mp3/mp3-reader.ts @@ -7,6 +7,7 @@ */ import { MP3_FRAME_HEADER_SIZE, getMp3ChannelCount, Mp3FrameHeader, readMp3FrameHeader } from '../../shared/mp3-misc'; +import { isThenable } from '../misc'; import { Reader, readU32Be } from '../reader'; export const readNextMp3FrameHeader = async ( @@ -27,7 +28,7 @@ export const readNextMp3FrameHeader = async ( : CHUNK_SIZE; let slice = reader.requestSliceRange(currentPos, MP3_FRAME_HEADER_SIZE, maxLength); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice || slice.length < MP3_FRAME_HEADER_SIZE) break; while (slice.remainingLength >= MP3_FRAME_HEADER_SIZE) { diff --git a/src/mpeg-ts/mpeg-ts-demuxer.ts b/src/mpeg-ts/mpeg-ts-demuxer.ts index 54635cd..7474a59 100644 --- a/src/mpeg-ts/mpeg-ts-demuxer.ts +++ b/src/mpeg-ts/mpeg-ts-demuxer.ts @@ -63,6 +63,7 @@ import { COLOR_PRIMARIES_MAP_INVERSE, findLastIndex, floorToMultiple, + isThenable, last, MATRIX_COEFFICIENTS_MAP_INVERSE, readExpGolomb, @@ -190,7 +191,7 @@ export class MpegTsDemuxer extends Demuxer { return this.metadataPromise ??= (async () => { const lengthToCheck = TS_PACKET_SIZE + 16 + 1; let startingSlice = this.reader.requestSlice(0, lengthToCheck); - if (startingSlice instanceof Promise) startingSlice = await startingSlice; + if (isThenable(startingSlice)) startingSlice = await startingSlice; assert(startingSlice); const startingBytes = readBytes(startingSlice, lengthToCheck); @@ -951,7 +952,7 @@ export class MpegTsDemuxer extends Demuxer { async readPacketHeader(pos: number): Promise { let slice = this.reader.requestSlice(pos, 4); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; @@ -987,7 +988,7 @@ export class MpegTsDemuxer extends Demuxer { async readPacket(pos: number): Promise { // Code in here is duplicated from readPacketHeader for performance reasons let slice = this.reader.requestSlice(pos, TS_PACKET_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; @@ -2099,7 +2100,7 @@ class PacketReadingContext { while (true) { let remaining = this.ensureBuffered(CHUNK_SIZE); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining === 0) { break; @@ -2253,7 +2254,7 @@ class PacketReadingContext { while (true) { let remaining = this.ensureBuffered(CHUNK_SIZE); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; const startPos = this.currentPos; @@ -2269,7 +2270,7 @@ class PacketReadingContext { const possibleHeaderStartPos = this.currentPos; let remaining = this.ensureBuffered(MAX_ADTS_FRAME_HEADER_SIZE); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < MAX_ADTS_FRAME_HEADER_SIZE) { return; @@ -2282,7 +2283,7 @@ class PacketReadingContext { this.seekTo(possibleHeaderStartPos); let remaining = this.ensureBuffered(header.frameLength); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; return this.supplyPacket( remaining, @@ -2300,7 +2301,7 @@ class PacketReadingContext { const possibleHeaderStartPos = this.currentPos; let remaining = this.ensureBuffered(MP3_FRAME_HEADER_SIZE); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < MP3_FRAME_HEADER_SIZE) { return; @@ -2314,7 +2315,7 @@ class PacketReadingContext { this.seekTo(possibleHeaderStartPos); let remaining = this.ensureBuffered(result.header.totalSize); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; const duration = result.header.audioSamplesInFrame * TIMESCALE / elementaryStream.info.sampleRate; @@ -2332,7 +2333,7 @@ class PacketReadingContext { // Need at least 5 bytes for sync word + CRC + fscod/frmsizecod let remaining = this.ensureBuffered(5); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < 5) { return; @@ -2361,7 +2362,7 @@ class PacketReadingContext { this.seekTo(possibleSyncPos); remaining = this.ensureBuffered(frameSize); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; const duration = Math.round( AC3_SAMPLES_PER_FRAME * TIMESCALE / elementaryStream.info.sampleRate, @@ -2377,7 +2378,7 @@ class PacketReadingContext { // Need at least 5 bytes for E-AC-3 header parsing (sync word + frmsiz + fscod/numblkscod) let remaining = this.ensureBuffered(5); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < 5) { return; @@ -2399,7 +2400,7 @@ class PacketReadingContext { this.seekTo(possibleSyncPos); remaining = this.ensureBuffered(frameSize); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; // Duration = numblks * 256 samples per block const samplesPerFrame = numblks * 256; @@ -2416,7 +2417,7 @@ class PacketReadingContext { const possibleSyncPos = this.currentPos; let remaining = this.ensureBuffered(DTS_CORE_FRAME_HEADER_SIZE); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < DTS_CORE_FRAME_HEADER_SIZE) { return; @@ -2438,7 +2439,7 @@ class PacketReadingContext { const headerBound = Math.min(leadingExss.frameSize, DTS_EXSS_MAX_HEADER_SIZE); let remaining = this.ensureBuffered(headerBound); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; leadingExss = parseDtsExssHeader(this.readBytes(remaining)) ?? leadingExss; } @@ -2456,7 +2457,7 @@ class PacketReadingContext { const neededBytes = nextSubstreamPos + DTS_EXSS_HEADER_PREFIX_SIZE; let remaining = this.ensureBuffered(neededBytes); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; if (remaining < neededBytes) { break; @@ -2484,7 +2485,7 @@ class PacketReadingContext { this.seekTo(possibleSyncPos); remaining = this.ensureBuffered(frameSize); - if (remaining instanceof Promise) remaining = await remaining; + if (isThenable(remaining)) remaining = await remaining; const duration = Math.round( sampleCount * TIMESCALE / elementaryStream.info.sampleRate, diff --git a/src/ogg/ogg-demuxer.ts b/src/ogg/ogg-demuxer.ts index b3fe01e..70ab3b8 100644 --- a/src/ogg/ogg-demuxer.ts +++ b/src/ogg/ogg-demuxer.ts @@ -18,6 +18,7 @@ import { AsyncMutex, binarySearchLessOrEqual, findLast, + isThenable, last, roundIfAlmostInteger, toDataView, @@ -72,7 +73,7 @@ export class OggDemuxer extends Demuxer { while (true) { let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const page = readPageHeader(slice); @@ -274,7 +275,7 @@ export class OggDemuxer extends Demuxer { while (true) { // Load the entire page data let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); - if (pageSlice instanceof Promise) pageSlice = await pageSlice; + if (isThenable(pageSlice)) pageSlice = await pageSlice; assert(pageSlice); const pageData = readBytes(pageSlice, currentPage.dataSize); @@ -299,7 +300,7 @@ export class OggDemuxer extends Demuxer { let currentPos = currentPage.headerStartPos + currentPage.totalSize; while (true) { let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; if (!headerSlice) { return null; } @@ -358,7 +359,7 @@ export class OggDemuxer extends Demuxer { let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; while (true) { let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; } @@ -658,7 +659,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking { ); let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); - if (searchSlice instanceof Promise) searchSlice = await searchSlice; + if (isThenable(searchSlice)) searchSlice = await searchSlice; assert(searchSlice); const found = findNextPageHeader(searchSlice, until); @@ -672,7 +673,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking { MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE, ); - if (headerSlice instanceof Promise) headerSlice = await headerSlice; + if (isThenable(headerSlice)) headerSlice = await headerSlice; assert(headerSlice); const page = readPageHeader(headerSlice); @@ -685,7 +686,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking { pageValid = true; } else { let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); - if (pageSlice instanceof Promise) pageSlice = await pageSlice; + if (isThenable(pageSlice)) pageSlice = await pageSlice; assert(pageSlice); // Validate the page by checking checksum @@ -759,7 +760,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking { const nextPos = currentPage.headerStartPos + currentPage.totalSize; let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; assert(slice); const nextPage = readPageHeader(slice); diff --git a/src/output.ts b/src/output.ts index 2c8329b..5a22d36 100644 --- a/src/output.ts +++ b/src/output.ts @@ -6,7 +6,16 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { assert, AsyncMutex, EventEmitter, isIso639Dash2LanguageCode, MaybePromise, Rotation, toArray } from './misc'; +import { + assert, + AsyncMutex, + EventEmitter, + isIso639Dash2LanguageCode, + isThenable, + MaybePromise, + Rotation, + toArray, +} from './misc'; import { MetadataTags, TrackDisposition, validateMetadataTags, validateTrackDisposition } from './metadata'; import { Muxer } from './muxer'; import { OutputFormat } from './output-format'; @@ -451,7 +460,7 @@ export class Output< } const rootTargetResult = this._getRootTarget(); - if (rootTargetResult instanceof Promise) { + if (isThenable(rootTargetResult)) { throw new TypeError(errorMessage); } @@ -516,7 +525,7 @@ export class Output< return result; }; - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(handleResult); } else { return handleResult(result); @@ -604,7 +613,7 @@ export class Output< return target; }; - if (result instanceof Promise) { + if (isThenable(result)) { return this._rootTargetPromise = result.then(handleResult); } else { return handleResult(result); diff --git a/src/reader.ts b/src/reader.ts index 3e909c9..5865295 100644 --- a/src/reader.ts +++ b/src/reader.ts @@ -7,7 +7,7 @@ */ import { InputDisposedError } from './input'; -import { assert, clamp, getUint24, MaybePromise, textDecoder, toDataView } from './misc'; +import { assert, clamp, getUint24, isThenable, MaybePromise, textDecoder, toDataView } from './misc'; import { DEFAULT_MAX_READ_POSITION, DEFAULT_MIN_READ_POSITION, Source } from './source'; export class Reader { @@ -47,7 +47,7 @@ export class Reader { const end = start + length; const result = this.source._read(start, end, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); - if (result instanceof Promise) { + if (isThenable(result)) { return result.then((x) => { if (!x) { return null; @@ -95,7 +95,7 @@ export class Reader { ); }; - if (promisedAttempt instanceof Promise) { + if (isThenable(promisedAttempt)) { return promisedAttempt.then(handleAttempt); } else { return handleAttempt(promisedAttempt); @@ -121,7 +121,7 @@ export class Reader { } let slice = this.requestSliceRange(currentSize, 0, CHUNK_SIZE); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice || slice.length === 0) { break; diff --git a/src/sample.ts b/src/sample.ts index 84bb869..7ecc9eb 100644 --- a/src/sample.ts +++ b/src/sample.ts @@ -11,6 +11,7 @@ import { clamp, COLOR_PRIMARIES_MAP, isAllowSharedBufferSource, + isThenable, MATRIX_COEFFICIENTS_MAP, Rotation, SECOND_TO_MICROSECOND_FACTOR, @@ -864,7 +865,7 @@ export class VideoSample implements Disposable { if (this._data instanceof VideoSampleResource) { let result = this._data.getDataPlanes(); - if (result instanceof Promise) result = await result; + if (isThenable(result)) result = await result; if ( !Array.isArray(result) @@ -1022,7 +1023,7 @@ export class VideoSample implements Disposable { } const planes = this._data.getDataPlanes(); - if (planes instanceof Promise) { + if (isThenable(planes)) { throw new Error( 'Cannot convert a VideoSampleResource-backed VideoSample to VideoFrame if getDataPlanes() returns' + ' a promise.', @@ -1586,7 +1587,7 @@ export class VideoSample implements Disposable { // Description's finalized; let's see if a registered transformer wants to handle it for (const transformer of registeredVideoSampleTransformers) { let result = transformer(this, description); - if (result instanceof Promise) result = await result; + if (isThenable(result)) result = await result; if (result !== null) { return result; diff --git a/src/source.ts b/src/source.ts index 1cd4a45..6bab482 100644 --- a/src/source.ts +++ b/src/source.ts @@ -14,6 +14,7 @@ import { closedIntervalsOverlap, FilePath, isNumber, + isThenable, isWebKit, MaybePromise, mergeRequestInit, @@ -328,7 +329,7 @@ export abstract class PathedSource extends Source { return ref; }; - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(handle); } else { return handle(result); @@ -387,7 +388,7 @@ export class CustomPathedSource extends PathedSource { return ref; }; - if (result instanceof Promise) { + if (isThenable(result)) { this._rootRequest = result.then(handle); } else { handle(result); @@ -894,7 +895,7 @@ export class UrlSource extends PathedSource { return result; }; - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(processResult); } else { return processResult(result); @@ -1198,7 +1199,7 @@ export class UrlSource extends PathedSource { for (const slice of uniqueSlices) { const result = backing._read(slice.start, slice.start + slice.bytes.length); - if (result instanceof Promise) { + if (isThenable(result)) { result.then((readResult) => { if (readResult) { // The backing's cache is empty at this point, so the read is guaranteed to produce @@ -1459,7 +1460,7 @@ export class CustomSource extends Source { const result = this._options.getSize(); - if (result instanceof Promise) { + if (isThenable(result)) { return result.then((size) => { if (!Number.isInteger(size) || size < 0) { throw new TypeError('options.getSize must return or resolve to a non-negative integer.'); @@ -1485,7 +1486,7 @@ export class CustomSource extends Source { const originalTargetPos = worker.targetPos; let data = this._options.read(worker.currentPos, originalTargetPos); - if (data instanceof Promise) data = await data; + if (isThenable(data)) data = await data; if (worker.aborted) { break; @@ -2706,7 +2707,7 @@ export class RangedSource extends Source { return result; }; - if (result instanceof Promise) { + if (isThenable(result)) { return result.then(processResult); } else { return processResult(result); diff --git a/src/wave/wave-demuxer.ts b/src/wave/wave-demuxer.ts index ddf750a..13e8892 100644 --- a/src/wave/wave-demuxer.ts +++ b/src/wave/wave-demuxer.ts @@ -12,7 +12,7 @@ import { Input } from '../input'; import { InputAudioTrackBacking } from '../input-track'; import { PacketRetrievalOptions } from '../media-sink'; import { DEFAULT_TRACK_DISPOSITION, MetadataTags } from '../metadata'; -import { assert, UNDETERMINED_LANGUAGE } from '../misc'; +import { assert, isThenable, UNDETERMINED_LANGUAGE } from '../misc'; import { EncodedPacket, PLACEHOLDER_DATA } from '../packet'; import { readAscii, readBytes, Reader, readU16, readU32, readU64 } from '../reader'; import { ID3_V2_HEADER_SIZE, parseId3V2Tag, readId3V2Header } from '../id3'; @@ -52,7 +52,7 @@ export class WaveDemuxer extends Demuxer { async readMetadata() { return this.metadataPromise ??= (async () => { let slice = this.reader.requestSlice(0, 12); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; assert(slice); const riffType = readAscii(slice, 4); @@ -77,7 +77,7 @@ export class WaveDemuxer extends Demuxer { while (totalFileSize === null || currentPos < totalFileSize) { let slice = this.reader.requestSlice(currentPos, 8); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) break; const chunkId = readAscii(slice, 4); @@ -103,7 +103,7 @@ export class WaveDemuxer extends Demuxer { // File and data chunk sizes are defined in here instead let ds64Slice = this.reader.requestSlice(startPos, chunkSize); - if (ds64Slice instanceof Promise) ds64Slice = await ds64Slice; + if (isThenable(ds64Slice)) ds64Slice = await ds64Slice; if (!ds64Slice) break; const riffChunkSize = readU64(ds64Slice, littleEndian); @@ -136,7 +136,7 @@ export class WaveDemuxer extends Demuxer { private async parseFmtChunk(startPos: number, size: number, littleEndian: boolean) { let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return; // File too short let formatTag = readU16(slice, littleEndian); @@ -206,7 +206,7 @@ export class WaveDemuxer extends Demuxer { private async parseListChunk(startPos: number, size: number, littleEndian: boolean) { let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return; // File too short const infoType = readAscii(slice, 4); @@ -303,7 +303,7 @@ export class WaveDemuxer extends Demuxer { private async parseId3Chunk(startPos: number, size: number) { // Parse ID3 tag embedded in WAV file (non-default, but used a lot in practice anyway) let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) return; // File too short const id3V2Header = readId3V2Header(slice); @@ -489,7 +489,7 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking { // requested slice actually exists. let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; if (!slice) { return null; @@ -501,7 +501,7 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking { data = PLACEHOLDER_DATA; } else { let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) slice = await slice; + if (isThenable(slice)) slice = await slice; assert(slice); data = readBytes(slice, sizeInBytes);