提问人:JSmith 提问时间:4/28/2023 最后编辑:JSmith 更新时间:5/5/2023 访问量:272
如何在javascript中实现抖动缓冲区以进行实时音频处理
How can I implement a jitter buffer in javascript for realtime audio processing
问:
我有一个发送器和一个在本地主机上运行的接收者
发射和接收的平均间隔分别为 2.89 和 2.92 毫秒。
正确的常数区间应为 2.90;
因此,我尝试实现某种环形缓冲区,其中缓冲区大小为 128,是数据块的大小和内存中保存的数据块的数量(延迟)。128 * N
N
我还没有评估接收和处理之间的时间间隔,但根据我设法计算的数据,大小的缓冲区应该足够了。N = 2
此外,我的缓冲区非常简单,它是一个 FIFO,如果在缓冲区已满时接收到值,它会替换前一个块。
为了获得正确的声音,我需要使缓冲区大小为 所以我的问题是如何实现一个可能具有自适应性的低延迟抖动缓冲区N = 16
我想目前缓冲区增加了额外的内存来管理平均变化,但我需要的是一种“就地”纠正变化的技术。
我目前的实现
_buffer = [];
BUFFER_SIZE = 8;
_isStarted = false;
readIndex = -1
//this callback is triggered any time a packet is received.
_onReceivePacket = ( event ) => {
let chunks = [];
//chunk length = 128
for ( let chunk of event.data ) {
chunks.push( new Float32Array( chunk ) );
}
if ( this._buffer.length < this.BUFFER_SIZE ) {
this._buffer.unshift( chunks );
this.readIndex++;
} else {
this._buffer.splice( 0, 1 );
this._buffer.unshift( chunks );
this._isStarted = true;
}
}
//this function copies the buffer into the playout output stream
_pullOut ( output ) {
try {
for ( let i = 0; i < output.length; i++ ) {
const channel = output[ i ];
for ( let j = 0; j < channel.length; j++ ) {
channel[ j ] = this._buffer[ this.readIndex ][ i ][ j ];
}
}
if ( this.readIndex - 1 !== -1 ) {
this._buffer.splice( this.readIndex, 1 );
this.readIndex--;
}
} catch ( e ) {
console.log( e, this._buffer, this.readIndex );
}
}
答:
0赞
Pradnya Kulkarni
5/5/2023
#1
你可以用 JavaScript 编写一些类,如下所示
class JitterBuffer {
constructor(bufferSize, latency) {
this.bufferSize = bufferSize; // Size of each data chunk
this.latency = latency; // Number of data chunks kept in memory
this.buffer = new Array(latency);
this.head = 0; // Index of the next available slot in the buffer
this.tail = 0; // Index of the next data chunk to be processed
this.fillCount = 0; // Number of data chunks currently in the buffer
this.interval = 2.90; // Target time interval between data chunks
this.timer = null; // Reference to the setInterval timer
}
start() {
// Start the timer to check for buffer underflow and adjust the fillCount
this.timer = setInterval(() => {
if (this.fillCount === 0) {
return;
}
const now = Date.now();
const expectedTime = this.tail * this.interval;
const actualTime = now - this.buffer[this.tail].timestamp;
if (actualTime >= expectedTime) {
// Remove the oldest data chunk and update the tail index
this.tail = (this.tail + 1) % this.latency;
this.fillCount--;
}
}, Math.floor(this.interval / 2));
}
stop() {
// Stop the timer
clearInterval(this.timer);
this.timer = null;
}
push(data) {
// Add the data chunk to the buffer and update the head index
this.buffer[this.head] = {
data,
timestamp: Date.now(),
};
this.head = (this.head + 1) % this.latency;
if (this.fillCount < this.latency) {
// Increment the fillCount if the buffer is not full yet
this.fillCount++;
} else {
// Replace the oldest data chunk and update the tail index
this.tail = (this.tail + 1) % this.latency;
}
}
shift() {
if (this.fillCount === 0) {
return null;
}
// Get the next data chunk to be processed and update the tail index
const dataChunk = this.buffer[this.tail].data;
this.tail = (this.tail + 1) % this.latency;
this.fillCount--;
return dataChunk;
}
adjustInterval(actualInterval) {
// Adjust the target time interval based on the actual interval
const delta = actualInterval - this.interval;
this.interval += delta / 8; // Adapt to 1/8th of the difference
}
}
它可以像下面这样使用:
// Create a jitter buffer with a buffer size of 128 bytes per chunk and a latency of 16 chunks
const jitterBuffer = new JitterBuffer(128, 16);
// Start the jitter buffer timer
jitterBuffer.start();
// Add some data to the jitter buffer
const data = new Uint8Array(128);
jitterBuffer.push(data);
// Retrieve the next data chunk from the jitter buffer
const nextChunk = jitterBuffer.shift();
// Stop the jitter buffer timer
jitterBuffer.stop();
评论
0赞
JSmith
5/6/2023
感谢您抽出宝贵时间接受采访。我有时间的时候会测试一下。
下一个:R Geom 抖动标记点
评论