/* Audio format reader is part of 3LAS (Low Latency Live Audio Streaming) https://github.com/JoJoBond/3LAS */ var AudioFormatReader = /** @class */ (function () { function AudioFormatReader(audio, logger, errorCallback, beforeDecodeCheck, dataReadyCallback) { if (!audio) throw new Error('AudioFormatReader: audio must be specified'); // Check callback argument if (typeof errorCallback !== 'function') throw new Error('AudioFormatReader: errorCallback must be specified'); if (typeof beforeDecodeCheck !== 'function') throw new Error('AudioFormatReader: beforeDecodeCheck must be specified'); if (typeof dataReadyCallback !== 'function') throw new Error('AudioFormatReader: dataReadyCallback must be specified'); this.Audio = audio; this.Logger = logger; this.ErrorCallback = errorCallback; this.BeforeDecodeCheck = beforeDecodeCheck; this.DataReadyCallback = dataReadyCallback; this.Id = 0; this.LastPushedId = -1; this.Samples = new Array(); this.BufferStore = {}; this.DataBuffer = new Uint8Array(0); } // Pushes frame data into the buffer AudioFormatReader.prototype.PushData = function (data) { // Append data to framedata buffer this.DataBuffer = this.ConcatUint8Array(this.DataBuffer, data); // Try to extract frames this.ExtractAll(); }; // Check if samples are available AudioFormatReader.prototype.SamplesAvailable = function () { return (this.Samples.length > 0); }; // Get a single bunch of sampels from the reader AudioFormatReader.prototype.PopSamples = function () { if (this.Samples.length > 0) { // Get first bunch of samples, remove said bunch from the array and hand it back to callee return this.Samples.shift(); } else return null; }; // Deletes all encoded and decoded data from the reader (does not effect headers, etc.) AudioFormatReader.prototype.PurgeData = function () { this.Id = 0; this.LastPushedId = -1; this.Samples = new Array(); this.BufferStore = {}; this.DataBuffer = new Uint8Array(0); }; // Used to force frame extraction externaly AudioFormatReader.prototype.Poke = function () { this.ExtractAll(); }; // Deletes all data from the reader (does effect headers, etc.) AudioFormatReader.prototype.Reset = function () { this.PurgeData(); }; // Extracts and converts the raw data AudioFormatReader.prototype.ExtractAll = function () { }; // Checks if a decode makes sense AudioFormatReader.prototype.OnBeforeDecode = function (id, duration) { return true; //TODO Fix this /* if(this.BeforeDecodeCheck(duration)) { return true; } else { this.OnDataReady(id, this.Audio.createBuffer(1, Math.ceil(duration * this.Audio.sampleRate), this.Audio.sampleRate)); return false; } */ }; // Stores the converted bnuches of samples in right order AudioFormatReader.prototype.OnDataReady = function (id, audioBuffer) { if (this.LastPushedId + 1 == id) { // Push samples into array this.Samples.push(audioBuffer); this.LastPushedId++; while (this.BufferStore[this.LastPushedId + 1]) { // Push samples we decoded earlier in correct order this.Samples.push(this.BufferStore[this.LastPushedId + 1]); delete this.BufferStore[this.LastPushedId + 1]; this.LastPushedId++; } // Callback to tell that data is ready this.DataReadyCallback(); } else { // Is out of order, will be pushed later this.BufferStore[id] = audioBuffer; } }; // Used to concatenate two Uint8Array (b comes BEHIND a) AudioFormatReader.prototype.ConcatUint8Array = function (a, b) { var tmp = new Uint8Array(a.length + b.length); tmp.set(a, 0); tmp.set(b, a.length); return tmp; }; AudioFormatReader.CanDecodeTypes = function (mimeTypes) { var audioTag = new Audio(); var result = false; for (var i = 0; i < mimeTypes.length; i++) { var mimeType = mimeTypes[i]; var answer = audioTag.canPlayType(mimeType); if (answer != "probably" && answer != "maybe") continue; result = true; break; } audioTag = null; return result; }; AudioFormatReader.DefaultSettings = function () { var settings = {}; // WAV settings["wav"] = {}; // Duration of wave samples to decode together settings["wav"]["BatchDuration"] = 1 / 10; // 0.1 seconds /* if (isAndroid && isNativeChrome) settings["wav"]["BatchDuration"] = 96 / 375; else if (isAndroid && isFirefox) settings["wav"]["BatchDuration"] = 96 / 375; else settings["wav"]["BatchDuration"] = 16 / 375; */ // Duration of addtional samples to decode to account for edge effects settings["wav"]["ExtraEdgeDuration"] = 1 / 300; // 0.00333... seconds /* if (isAndroid && isNativeChrome) settings["wav"]["ExtraEdgeDuration"] = 1 / 1000; else if (isAndroid && isFirefox) settings["wav"]["ExtraEdgeDuration"] = 1 / 1000; else settings["wav"]["ExtraEdgeDuration"] = 1 / 1000; */ // MPEG settings["mpeg"] = {}; // Adds a minimal ID3v2 tag before decoding frames. settings["mpeg"]["AddID3Tag"] = false; // Minimum number of frames to decode together // Theoretical minimum is 2. // Recommended value is 3 or higher. if (isAndroid) settings["mpeg"]["MinDecodeFrames"] = 3; else settings["mpeg"]["MinDecodeFrames"] = 3; return settings; }; AudioFormatReader.Create = function (mime, audio, logger, errorCallback, beforeDecodeCheck, dataReadyCallback, settings) { if (settings === void 0) { settings = null; } if (typeof mime !== "string") throw new Error('CreateAudioFormatReader: Invalid MIME-Type, must be string'); if (!settings) settings = this.DefaultSettings(); var fullMime = mime; if (mime.indexOf("audio/pcm") == 0) mime = "audio/pcm"; // Load format handler according to MIME-Type switch (mime.replace(/\s/g, "")) { // MPEG Audio (mp3) case "audio/mpeg": case "audio/MPA": case "audio/mpa-robust": if (!AudioFormatReader.CanDecodeTypes(new Array("audio/mpeg", "audio/MPA", "audio/mpa-robust"))) throw new Error('CreateAudioFormatReader: Browser can not decode specified MIME-Type (' + mime + ')'); return new AudioFormatReader_MPEG(audio, logger, errorCallback, beforeDecodeCheck, dataReadyCallback, settings["mpeg"]["AddID3Tag"], settings["mpeg"]["MinDecodeFrames"]); break; // Waveform Audio File Format case "audio/vnd.wave": case "audio/wav": case "audio/wave": case "audio/x-wav": if (!AudioFormatReader.CanDecodeTypes(new Array("audio/wav", "audio/wave"))) throw new Error('CreateAudioFormatReader: Browser can not decode specified MIME-Type (' + mime + ')'); return new AudioFormatReader_WAV(audio, logger, errorCallback, beforeDecodeCheck, dataReadyCallback, settings["wav"]["BatchDuration"], settings["wav"]["ExtraEdgeDuration"]); break; // Unknown codec default: throw new Error('CreateAudioFormatReader: Specified MIME-Type (' + mime + ') not supported'); break; } }; return AudioFormatReader; }());