replace with a more robust state engine implementation

This commit is contained in:
Jakob Ketterl 2023-01-28 16:37:32 +01:00
parent d79a1396a6
commit b1ac8caf9b
1 changed files with 34 additions and 25 deletions

View File

@ -331,7 +331,9 @@ ImaAdpcmCodec.prototype.reset = function() {
this.synchronized = 0; this.synchronized = 0;
this.syncWord = "SYNC"; this.syncWord = "SYNC";
this.syncCounter = 0; this.syncCounter = 0;
this.skip = 0; this.phase = 0;
this.syncBuffer = new Uint8Array(4);
this.syncBufferIndex = 0;
}; };
ImaAdpcmCodec.imaIndexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 ]; ImaAdpcmCodec.imaIndexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 ];
@ -359,38 +361,45 @@ ImaAdpcmCodec.prototype.decode = function(data) {
ImaAdpcmCodec.prototype.decodeWithSync = function(data) { ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
var output = new Int16Array(data.length * 2); var output = new Int16Array(data.length * 2);
var index = this.skip;
var oi = 0; var oi = 0;
while (index < data.length) { for (var index = 0; index < data.length; index++) {
while (this.synchronized < 4 && index < data.length) { switch (this.phase) {
if (data[index] === this.syncWord.charCodeAt(this.synchronized)) { case 0:
this.synchronized++; // search for sync word
} else { if (data[index] !== this.syncWord.charCodeAt(this.synchronized++)) {
this.synchronized = 0; // reset if data is unexpected
} this.synchronized = 0;
index++; }
if (this.synchronized === 4) { // if sync word has been found pass on to next phase
if (index + 4 < data.length) { if (this.synchronized === 4) {
var syncData = new Int16Array(data.buffer.slice(index, index + 4)); this.syncBufferIndex = 0;
this.phase = 1;
}
break;
case 1:
// read codec runtime data from stream
this.syncBuffer[this.syncBufferIndex++] = data[index];
// if data is complete, apply and pass on to next phase
if (this.syncBufferIndex === 4) {
var syncData = new Int16Array(this.syncBuffer.buffer);
this.stepIndex = syncData[0]; this.stepIndex = syncData[0];
this.predictor = syncData[1]; this.predictor = syncData[1];
this.syncCounter = 1000;
this.phase = 2;
} }
this.syncCounter = 1000;
index += 4;
break; break;
} case 2:
} // decode actual audio data
while (index < data.length) { output[oi++] = this.decodeNibble(data[index] & 0x0F);
if (this.syncCounter-- < 0) { output[oi++] = this.decodeNibble(data[index] >> 4);
this.synchronized = 0; // if the next sync keyword is due, reset and return to phase 0
if (this.syncCounter-- === 0) {
this.synchronized = 0;
this.phase = 0;
}
break; break;
}
output[oi++] = this.decodeNibble(data[index] & 0x0F);
output[oi++] = this.decodeNibble(data[index] >> 4);
index++;
} }
} }
this.skip = index - data.length;
return output.slice(0, oi); return output.slice(0, oi);
}; };