/*
    Socket fallback is part of 3LAS (Low Latency Live Audio Streaming)
    https://github.com/JoJoBond/3LAS
*/
var Fallback_Settings = /** @class */ (function () {
    function Fallback_Settings() {
        this.Formats = [
            { "Mime": "audio/mpeg", "Name": "mp3" },
            { "Mime": "audio/wave", "Name": "wav" }
        ];
        this.MaxVolume = 1.0;
        this.AutoCorrectSpeed = false;
        this.InitialBufferLength = 1.0 / 3.0;
    }
    return Fallback_Settings;
}());
var Fallback = /** @class */ (function () {
    function Fallback(logger, settings) {
        this.Logger = logger;
        if (!this.Logger) {
            this.Logger = new Logging(null, null);
        }
        // Create audio context
        if (typeof AudioContext !== "undefined")
            this.Audio = new AudioContext();
        else if (typeof webkitAudioContext !== "undefined")
            this.Audio = new webkitAudioContext();
        else if (typeof mozAudioContext !== "undefined")
            this.Audio = new mozAudioContext();
        else {
            this.Logger.Log('3LAS: Browser does not support "AudioContext".');
            throw new Error();
        }
        this.Settings = settings;
        this.Logger.Log("Detected: " +
            (OSName == "MacOSX" ? "Mac OSX" : (OSName == "Unknown" ? "Unknown OS" : OSName)) + ", " +
            (BrowserName == "IE" ? "Internet Explorer" : (BrowserName == "NativeChrome" ? "Chrome legacy" : (BrowserName == "Unknown" ? "Unknown Browser" : BrowserName))));
        this.SelectedFormatMime = "";
        this.SelectedFormatName = "";
        for (var i = 0; i < this.Settings.Formats.length; i++) {
            if (!AudioFormatReader.CanDecodeTypes([this.Settings.Formats[i].Mime]))
                continue;
            this.SelectedFormatMime = this.Settings.Formats[i].Mime;
            this.SelectedFormatName = this.Settings.Formats[i].Name;
            break;
        }
        if (this.SelectedFormatMime == "" || this.SelectedFormatName == "") {
            this.Logger.Log("None of the available MIME types are supported.");
            throw new Error();
        }
        this.Logger.Log("Using websocket fallback with MIME: " + this.SelectedFormatMime);
        try {
            this.Player = new LiveAudioPlayer(this.Audio, this.Logger, this.Settings.MaxVolume, this.Settings.InitialBufferLength, this.Settings.AutoCorrectSpeed);
            this.Logger.Log("Init of LiveAudioPlayer succeeded");
        }
        catch (e) {
            this.Logger.Log("Init of LiveAudioPlayer failed: " + e);
            throw new Error();
        }
        try {
            this.FormatReader = AudioFormatReader.Create(this.SelectedFormatMime, this.Audio, this.Logger, this.OnReaderError.bind(this), this.Player.CheckBeforeDecode, this.OnReaderDataReady.bind(this), AudioFormatReader.DefaultSettings());
            this.Logger.Log("Init of AudioFormatReader succeeded");
        }
        catch (e) {
            this.Logger.Log("Init of AudioFormatReader failed: " + e);
            throw new Error();
        }
        this.PacketModCounter = 0;
        this.LastCheckTime = 0;
        this.FocusChecker = 0;
    }
    Fallback.prototype.Init = function (webSocket) {
        this.MobileUnmute();
        this.WebSocket = webSocket;
        this.WebSocket?.Send(JSON.stringify({
            "type": "fallback",
            "data": this.SelectedFormatName
        }));
        this.StartFocusChecker();
    };
    Fallback.prototype.MobileUnmute = function () {
        var amplification = this.Audio.createGain();
        // Set volume to max
        amplification.gain.value = 1.0;
        // Connect gain node to context
        amplification.connect(this.Audio.destination);
        // Create one second buffer with silence		
        var audioBuffer = this.Audio.createBuffer(2, this.Audio.sampleRate, this.Audio.sampleRate);
        // Create new audio source for the buffer
        var sourceNode = this.Audio.createBufferSource();
        // Make sure the node deletes itself after playback
        sourceNode.onended = function (_ev) {
            sourceNode.disconnect();
            amplification.disconnect();
        };
        // Pass audio data to source
        sourceNode.buffer = audioBuffer;
        // Connect the source to the gain node
        sourceNode.connect(amplification);
        // Play source		
        sourceNode.start();
    };
    Object.defineProperty(Fallback.prototype, "Volume", {
        get: function () {
            return this.Player.Volume / this.Settings.MaxVolume;
        },
        set: function (value) {
            this.Player.Volume = value * this.Settings.MaxVolume;
        },
        enumerable: false,
        configurable: true
    });
    // Callback functions from format reader
    Fallback.prototype.OnReaderError = function () {
        this.Logger.Log("Reader error: Decoding failed.");
    };
    Fallback.prototype.OnReaderDataReady = function () {
        while (this.FormatReader.SamplesAvailable()) {
            this.Player.PushBuffer(this.FormatReader.PopSamples());
        }
    };
    // Callback function from socket connection
    Fallback.prototype.OnSocketError = function (message) {
    };
    Fallback.prototype.OnSocketConnect = function () {
    };
    Fallback.prototype.OnSocketDisconnect = function () {
    };
    Fallback.prototype.OnSocketDataReady = function (data) {
        this.PacketModCounter++;
        if (this.PacketModCounter > 100) {
            if (this.ActivityCallback)
                this.ActivityCallback();
            this.PacketModCounter = 0;
        }
        this.FormatReader.PushData(new Uint8Array(data));
    };
    Fallback.prototype.StartFocusChecker = function () {
        if (!this.FocusChecker) {
            this.LastCheckTime = Date.now();
            this.FocusChecker = window.setInterval(this.CheckFocus.bind(this), 2000);
        }
    };
    Fallback.prototype.StopFocusChecker = function () {
        if (this.FocusChecker) {
            window.clearInterval(this.FocusChecker);
            this.FocusChecker = 0;
        }
    };
    Fallback.prototype.CheckFocus = function () {
        var checkTime = Date.now();
        // Check if focus was lost
        if (checkTime - this.LastCheckTime > 10000) {
            // If so, drop all samples in the buffer
            this.Logger.Log("Focus lost, purging format reader.");
            this.FormatReader.PurgeData();
        }
        this.LastCheckTime = checkTime;
    };
    Fallback.prototype.Reset = function () {
        this.StopFocusChecker();
        this.FormatReader.Reset();
        this.Player.Reset();
        this.WebSocket = null;
    };
    return Fallback;
}());