fix: restore working transmit and listen logic from aa85dd9
- Use createScriptProcessor instead of Tone.UserMedia for transmit - Use analyser.getByteFrequencyData() for proper visualizer - Keep per-user timing with userTimelines Map for listen - Remove Tone.js dependencies from transmit - Restore proper AudioContext usage
This commit is contained in:
@@ -7,12 +7,10 @@ const state = {
|
|||||||
text: bootstrapData.messages || [],
|
text: bootstrapData.messages || [],
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
isListening: false,
|
isListening: false,
|
||||||
mic: null,
|
audioContextTransmit: null,
|
||||||
analyser: null,
|
|
||||||
meter: null,
|
|
||||||
synth: null,
|
|
||||||
nextStartTime: 0,
|
|
||||||
audioContextListen: null,
|
audioContextListen: null,
|
||||||
|
processor: null,
|
||||||
|
nextStartTime: 0,
|
||||||
userTimelines: new Map(),
|
userTimelines: new Map(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -356,50 +354,51 @@ function appendEmpty(parent, message) {
|
|||||||
|
|
||||||
async function startStreaming() {
|
async function startStreaming() {
|
||||||
try {
|
try {
|
||||||
await Tone.start();
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||||
state.mic = new Tone.UserMedia();
|
|
||||||
state.analyser = new Tone.Analyser('waveform');
|
|
||||||
state.meter = new Tone.Meter();
|
|
||||||
|
|
||||||
state.mic.connect(state.analyser);
|
|
||||||
state.mic.connect(state.meter);
|
|
||||||
|
|
||||||
await state.mic.open();
|
|
||||||
|
|
||||||
const analyzeInterval = setInterval(() => {
|
|
||||||
if (!state.isStreaming) {
|
|
||||||
clearInterval(analyzeInterval);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const level = state.meter.getValue();
|
|
||||||
updateVisualizer(Math.max(0, level + 100) / 100);
|
|
||||||
|
|
||||||
const waveform = state.analyser.getValue();
|
|
||||||
if (waveform && state.socket?.readyState === WebSocket.OPEN) {
|
|
||||||
const pcm = new Int16Array(waveform.length);
|
|
||||||
for (let i = 0; i < waveform.length; i++) {
|
|
||||||
pcm[i] = Math.max(-1, Math.min(1, waveform[i])) * 32767;
|
|
||||||
}
|
|
||||||
state.socket.send(pcm.buffer);
|
|
||||||
}
|
|
||||||
}, 50);
|
|
||||||
|
|
||||||
state.isStreaming = true;
|
state.isStreaming = true;
|
||||||
el.toggleBtn.textContent = 'Stop Transmitting';
|
el.toggleBtn.textContent = 'Stop Transmitting';
|
||||||
} catch (error) {
|
|
||||||
showError(`Microphone error: ${error.message}`);
|
state.audioContextTransmit = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: SAMPLE_RATE });
|
||||||
|
const source = state.audioContextTransmit.createMediaStreamSource(stream);
|
||||||
|
|
||||||
|
const analyser = state.audioContextTransmit.createAnalyser();
|
||||||
|
analyser.fftSize = 64;
|
||||||
|
source.connect(analyser);
|
||||||
|
const dataArray = new Uint8Array(analyser.frequencyBinCount);
|
||||||
|
|
||||||
|
state.processor = state.audioContextTransmit.createScriptProcessor(4096, 1, 1);
|
||||||
|
source.connect(state.processor);
|
||||||
|
state.processor.connect(state.audioContextTransmit.destination);
|
||||||
|
|
||||||
|
state.processor.onaudioprocess = (e) => {
|
||||||
|
if (!state.isStreaming || state.socket?.readyState !== WebSocket.OPEN) return;
|
||||||
|
|
||||||
|
const inputData = e.inputBuffer.getChannelData(0);
|
||||||
|
const pcmData = new Int16Array(inputData.length);
|
||||||
|
for (let i = 0; i < inputData.length; i++) {
|
||||||
|
pcmData[i] = Math.max(-1, Math.min(1, inputData[i])) * 32767;
|
||||||
|
}
|
||||||
|
state.socket.send(pcmData.buffer);
|
||||||
|
|
||||||
|
analyser.getByteFrequencyData(dataArray);
|
||||||
|
bars.forEach((bar, index) => {
|
||||||
|
const percent = (dataArray[index] / 255) * 100;
|
||||||
|
bar.style.height = `${Math.max(2, percent)}%`;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
showError(`Microphone access denied: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopStreaming() {
|
function stopStreaming() {
|
||||||
state.isStreaming = false;
|
state.isStreaming = false;
|
||||||
state.mic?.close();
|
if (state.processor) state.processor.disconnect();
|
||||||
state.mic = null;
|
if (state.audioContextTransmit) state.audioContextTransmit.close();
|
||||||
state.analyser = null;
|
state.processor = null;
|
||||||
state.meter = null;
|
state.audioContextTransmit = null;
|
||||||
el.toggleBtn.textContent = 'Start Transmitting';
|
el.toggleBtn.textContent = 'Start Transmitting';
|
||||||
updateVisualizer(0);
|
bars.forEach(bar => bar.style.height = '2px');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleListen() {
|
function toggleListen() {
|
||||||
|
|||||||
Reference in New Issue
Block a user