"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NtpTimeBase = void 0;
const crypto_1 = require("crypto");
const __1 = require("../..");
const webm_1 = require("./webm");
class NtpTimeBase {
    constructor(clockRate) {
        Object.defineProperty(this, "clockRate", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: clockRate
        });
        Object.defineProperty(this, "id", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (0, crypto_1.randomUUID)().toString()
        });
        Object.defineProperty(this, "baseNtpTimestamp", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "baseRtpTimestamp", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "latestNtpTimestamp", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "latestRtpTimestamp", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "currentElapsed", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 0
        });
        Object.defineProperty(this, "buffer", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        Object.defineProperty(this, "internalStats", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: {}
        });
        Object.defineProperty(this, "started", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: false
        });
    }
    toJSON() {
        return {
            ...this.internalStats,
            id: this.id,
            baseRtpTimestamp: this.baseRtpTimestamp,
            latestRtpTimestamp: this.latestRtpTimestamp,
            baseNtpTimestamp: this.baseNtpTimestamp && (0, __1.ntpTime2Sec)(this.baseNtpTimestamp),
            latestNtpTimestamp: this.latestNtpTimestamp && (0, __1.ntpTime2Sec)(this.latestNtpTimestamp),
            bufferLength: this.buffer.length,
            currentElapsed: this.currentElapsed,
            clockRate: this.clockRate,
        };
    }
    stop() {
        this.buffer = [];
        this.internalStats = {};
    }
    processInput({ rtcp, rtp, eol }) {
        if (eol) {
            this.stop();
            return [{ eol: true }];
        }
        if (rtcp && rtcp.type === __1.RtcpSrPacket.type) {
            const { ntpTimestamp, rtpTimestamp } = rtcp.senderInfo;
            this.latestNtpTimestamp = ntpTimestamp;
            this.latestRtpTimestamp = rtpTimestamp;
            if (this.baseNtpTimestamp == undefined) {
                this.baseNtpTimestamp = ntpTimestamp;
                this.baseRtpTimestamp = rtpTimestamp;
            }
            this.internalStats["ntpReceived"] = new Date().toISOString();
            this.started = true;
        }
        if (rtp) {
            this.buffer.push(rtp);
            this.internalStats["payloadType"] = rtp.header.payloadType;
            const res = [];
            if (this.baseRtpTimestamp == undefined ||
                this.baseNtpTimestamp == undefined ||
                this.latestNtpTimestamp == undefined ||
                this.latestRtpTimestamp == undefined) {
                return [];
            }
            for (const rtp of this.buffer) {
                const ntp = this.updateNtp(rtp.header.timestamp);
                const ms = ntp * 1000;
                const time = Math.round(ms);
                res.push({ rtp, time });
                this.internalStats["timeSource"] =
                    new Date().toISOString() + " time:" + time;
            }
            this.buffer = [];
            return res;
        }
        return [];
    }
    /**
     *
     * @param rtpTimestamp
     * @returns sec
     */
    calcNtp({ rtpTimestamp, baseNtpTimestamp, baseRtpTimestamp, elapsedOffset, }) {
        const rotate = Math.abs(rtpTimestamp - baseRtpTimestamp) > (webm_1.Max32Uint / 4) * 3;
        const elapsed = rotate
            ? rtpTimestamp + webm_1.Max32Uint - baseRtpTimestamp
            : rtpTimestamp - baseRtpTimestamp;
        const elapsedSec = elapsed / this.clockRate;
        // sec
        const ntp = (0, __1.ntpTime2Sec)(baseNtpTimestamp) + elapsedOffset + elapsedSec;
        return { ntp, elapsedSec };
    }
    updateNtp(rtpTimestamp) {
        this.internalStats["inputRtp"] = rtpTimestamp;
        const base = this.calcNtp({
            rtpTimestamp,
            baseNtpTimestamp: this.baseNtpTimestamp,
            baseRtpTimestamp: this.baseRtpTimestamp,
            elapsedOffset: this.currentElapsed,
        });
        const latest = this.calcNtp({
            rtpTimestamp,
            baseNtpTimestamp: this.latestNtpTimestamp,
            baseRtpTimestamp: this.latestRtpTimestamp,
            elapsedOffset: 0,
        });
        this.internalStats["calcBaseNtp"] = base.ntp;
        this.internalStats["calcLatestNtp"] = latest.ntp;
        if (base.ntp < latest.ntp) {
            // update baseNtp
            this.baseNtpTimestamp = this.latestNtpTimestamp;
            this.baseRtpTimestamp = this.latestRtpTimestamp;
            this.currentElapsed = 0;
            this.internalStats["calcNtp"] = latest.ntp;
            return latest.ntp;
        }
        else {
            this.currentElapsed += base.elapsedSec;
            this.baseRtpTimestamp = rtpTimestamp;
            this.internalStats["calcNtp"] = base.ntp;
            return base.ntp;
        }
    }
}
exports.NtpTimeBase = NtpTimeBase;
//# sourceMappingURL=ntpTime.js.map