1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00
Files
fm-dx-webserver/web/js/3las/fallback/3las.formatreader.js
NoobishSVK 2d59684c3f bugfixes
2024-02-19 21:49:20 +01:00

193 lines
8.0 KiB
JavaScript

/*
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;
}());