Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
Jakob Ketterl | 58c7f8a132 | |
Jakob Ketterl | a779d5d02a | |
Jakob Ketterl | a6f2b6b31a |
|
@ -1,5 +1,5 @@
|
|||
from csdr.chain import Chain
|
||||
from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, Limit
|
||||
from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, OpusEncoder, Limit
|
||||
from pycsdr.types import Format
|
||||
|
||||
|
||||
|
@ -27,10 +27,12 @@ class ClientAudioChain(Chain):
|
|||
workers += [converter]
|
||||
if compression == "adpcm":
|
||||
workers += [AdpcmEncoder(sync=True)]
|
||||
elif compression == "opus":
|
||||
workers += [OpusEncoder()]
|
||||
super().__init__(workers)
|
||||
|
||||
def _buildConverter(self):
|
||||
return Converter(self.format, self.inputRate, self.clientRate)
|
||||
return Converter(self.format, self.inputRate, 12000)
|
||||
|
||||
def _updateConverter(self):
|
||||
converter = self._buildConverter()
|
||||
|
@ -63,10 +65,18 @@ class ClientAudioChain(Chain):
|
|||
self._updateConverter()
|
||||
|
||||
def setAudioCompression(self, compression: str) -> None:
|
||||
index = self.indexOf(lambda x: isinstance(x, AdpcmEncoder))
|
||||
index = self.indexOf(lambda x: isinstance(x, AdpcmEncoder) or isinstance(x, OpusEncoder))
|
||||
newEncoder = None
|
||||
if compression == "adpcm":
|
||||
newEncoder = AdpcmEncoder(sync=True)
|
||||
elif compression == "opus":
|
||||
newEncoder = OpusEncoder()
|
||||
|
||||
if newEncoder:
|
||||
if index < 0:
|
||||
self.append(AdpcmEncoder(sync=True))
|
||||
self.append(newEncoder)
|
||||
else:
|
||||
self.replace(index, newEncoder)
|
||||
else:
|
||||
if index >= 0:
|
||||
self.remove(index)
|
||||
|
|
|
@ -21,7 +21,15 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
|||
me._start();
|
||||
}
|
||||
|
||||
this.audioCodec = new ImaAdpcmCodec();
|
||||
var onAudio = function(audioData) {
|
||||
me.playbackAudio(audioData);
|
||||
}
|
||||
|
||||
this.audioCodecs = {
|
||||
"adpcm": new ImaAdpcmCodec(onAudio),
|
||||
"opus": new OpusCodec(onAudio)
|
||||
};
|
||||
|
||||
this.compression = 'none';
|
||||
|
||||
this.setupResampling();
|
||||
|
@ -279,24 +287,26 @@ AudioEngine.prototype.getSampleRate = function() {
|
|||
AudioEngine.prototype.processAudio = function(data, resampler) {
|
||||
if (!this.audioNode) return;
|
||||
this.audioBytes.add(data.byteLength);
|
||||
var buffer;
|
||||
if (this.compression === "adpcm") {
|
||||
//resampling & ADPCM
|
||||
buffer = this.audioCodec.decodeWithSync(new Uint8Array(data));
|
||||
|
||||
if (this.compression !== "none") {
|
||||
this.audioCodecs[this.compression].decodeAsync(new Uint8Array(data));
|
||||
} else {
|
||||
buffer = new Int16Array(data);
|
||||
this.playbackAudio(new Int16Array(data));
|
||||
}
|
||||
buffer = resampler.process(buffer);
|
||||
}
|
||||
|
||||
AudioEngine.prototype.playbackAudio = function(audioData) {
|
||||
//var buffer = this.resampler.process(audioData);
|
||||
if (this.audioNode.port) {
|
||||
// AudioWorklets supported
|
||||
this.audioNode.port.postMessage(buffer);
|
||||
this.audioNode.port.postMessage(audioData);
|
||||
} else {
|
||||
// silently drop excess samples
|
||||
if (this.getBuffersize() + buffer.length <= this.maxBufferSize) {
|
||||
this.audioBuffers.push(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AudioEngine.prototype.pushAudio = function(data) {
|
||||
this.processAudio(data, this.resampler);
|
||||
|
@ -320,8 +330,9 @@ AudioEngine.prototype.getBuffersize = function() {
|
|||
return this.audioBuffers.map(function(b){ return b.length; }).reduce(function(a, b){ return a + b; }, 0);
|
||||
};
|
||||
|
||||
function ImaAdpcmCodec() {
|
||||
function ImaAdpcmCodec(callback) {
|
||||
this.reset();
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
ImaAdpcmCodec.prototype.reset = function() {
|
||||
|
@ -357,7 +368,7 @@ ImaAdpcmCodec.prototype.decode = function(data) {
|
|||
return output;
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
||||
ImaAdpcmCodec.prototype.decodeAsync = function(data, callback) {
|
||||
var output = new Int16Array(data.length * 2);
|
||||
var index = this.skip;
|
||||
var oi = 0;
|
||||
|
@ -391,7 +402,7 @@ ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
|||
}
|
||||
}
|
||||
this.skip = index - data.length;
|
||||
return output.slice(0, oi);
|
||||
this.callback(output.slice(0, oi));
|
||||
};
|
||||
|
||||
ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
||||
|
@ -412,6 +423,39 @@ ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
|||
return this.predictor;
|
||||
};
|
||||
|
||||
function OpusCodec(callback) {
|
||||
this.callback = callback;
|
||||
this.resetDecoder();
|
||||
}
|
||||
|
||||
OpusCodec.prototype.resetDecoder = function() {
|
||||
var me = this;
|
||||
me.decoder = new AudioDecoder({
|
||||
output: function(audioData) {
|
||||
var buffer = new Float32Array(audioData.numberOfFrames * audioData.numberOfChannels);
|
||||
audioData.copyTo(buffer, {planeIndex: 0});
|
||||
me.callback(buffer);
|
||||
},
|
||||
error: function(e) {
|
||||
console.error(e);
|
||||
me.resetDecoder();
|
||||
}
|
||||
});
|
||||
me.decoder.configure({
|
||||
codec: "opus",
|
||||
sampleRate: 12000,
|
||||
numberOfChannels: 1
|
||||
});
|
||||
}
|
||||
|
||||
OpusCodec.prototype.decodeAsync = function(data) {
|
||||
this.decoder.decode(new EncodedAudioChunk({
|
||||
type: "key",
|
||||
data: data,
|
||||
timestamp: 0
|
||||
}));
|
||||
};
|
||||
|
||||
function Interpolator(factor) {
|
||||
this.factor = factor;
|
||||
this.lowpass = new Lowpass(factor)
|
||||
|
|
|
@ -754,7 +754,7 @@ function on_ws_recv(evt) {
|
|||
if ('audio_compression' in config) {
|
||||
var audio_compression = config['audio_compression'];
|
||||
audioEngine.setCompression(audio_compression);
|
||||
divlog("Audio stream is " + ((audio_compression === "adpcm") ? "compressed" : "uncompressed") + ".");
|
||||
divlog("Audio stream is " + ((audio_compression !== "none") ? "compressed" : "uncompressed") + ".");
|
||||
}
|
||||
if ('fft_compression' in config) {
|
||||
fft_compression = config['fft_compression'];
|
||||
|
|
|
@ -132,6 +132,7 @@ class GeneralSettingsController(SettingsFormController):
|
|||
"Audio compression",
|
||||
options=[
|
||||
Option("adpcm", "ADPCM"),
|
||||
Option("opus", "OPUS"),
|
||||
Option("none", "None"),
|
||||
],
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue