Real-time voice interaction with AI models has moved from novelty to production necessity. Whether you're building an AI sales agent that responds in under 300ms, a competitive quiz platform with sub-100ms response windows, or a voice-first customer service system, the underlying technology stack matters enormously. In this hands-on engineering guide, I'll walk you through integrating HolySheep AI's relay infrastructure with WebRTC and OpenAI's Realtime API, covering the full architecture, working code samples, and the gotchas that cost me three days of debugging.
Comparison: HolySheep vs Official API vs Alternative Relay Services
| Feature | HolySheep AI Relay | Official OpenAI API | Generic WebSocket Relay |
|---|---|---|---|
| Endpoint Base | https://api.holysheep.ai/v1 | api.openai.com (direct) | Custom/self-hosted |
| Typical Latency | <50ms relay overhead | Variable (100-300ms+) | 20-80ms (infrastructure dependent) |
| Voice Model Support | GPT-4o Realtime, GPT-4.1 | Full OpenAI Realtime API | Limited/Custom |
| Pricing (Voice) | ¥1=$1 rate (85% savings vs ¥7.3) | Standard OpenAI pricing | Infrastructure + API costs |
| Payment Methods | WeChat, Alipay, Stripe | Credit card only | Varies |
| Free Credits | Yes, on signup | No | No |
| Bidirectional Streaming | Native WebRTC support | WebSocket only | Custom implementation |
| Geo-redundancy | APAC-optimized | Global | Self-managed |
Why This Stack for Real-Time Voice?
In my experience building production voice AI systems across 2025-2026, I've found that the "last mile" of audio delivery often matters more than the model itself. OpenAI's Realtime API delivers excellent conversational AI, but geographically distant users (especially in APAC) face latency spikes that break the illusion of natural conversation. HolySheep's relay infrastructure sits strategically positioned to reduce this overhead to under 50ms while maintaining full API compatibility.
Architecture Overview
- Client Side: WebRTC peer connection with audio tracks (microphone input, speaker output)
- Relay Layer: HolySheep WebRTC gateway → OpenAI Realtime API proxy
- Media Processing: Opus codec for efficient audio transport, optional noise suppression
- Session Management: Token-based authentication, session persistence for multi-turn conversations
Prerequisites
- HolySheep account with API key (Sign up here for free credits)
- Node.js 18+ or browser environment with WebRTC support
- OpenAI API access (configure via HolySheep dashboard)
- Basic familiarity with WebRTC concepts (RTCPeerConnection, ICE candidates, SDP)
Step-by-Step Implementation
1. Initialize the WebRTC Connection with HolySheep
The key insight that took me two days to discover: HolySheep's WebRTC gateway expects a specific signaling format. You don't connect directly to OpenAI—you connect to HolySheep's relay, which handles the protocol translation transparently.
// holy-sheep-webrtc-client.js
// HolySheep AI WebRTC + OpenAI Realtime API Integration
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY; // YOUR_HOLYSHEEP_API_KEY
class HolySheepRealtimeVoice {
constructor(options = {}) {
this.apiKey = options.apiKey || HOLYSHEEP_API_KEY;
this.model = options.model || 'gpt-4o-realtime';
this.audioContext = null;
this.peerConnection = null;
this.dataChannel = null;
this.audioQueue = [];
this.isConnected = false;
// Voice activity detection settings
this.vadThreshold = options.vadThreshold || 0.5;
this.vadSilenceTimeout = options.vadSilenceTimeout || 500; // ms
}
async connect() {
// Step 1: Get relay credentials from HolySheep
const credentials = await this.getRelayCredentials();
// Step 2: Create WebRTC peer connection
this.peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: credentials.iceServers }
]
});
// Step 3: Set up audio track for incoming AI responses
const audioTrack = new MediaStreamTrack();
this.peerConnection.addTrack(audioTrack);
// Step 4: Create data channel for control messages
this.dataChannel = this.peerConnection.createDataChannel('holy-sheep-control');
this.setupDataChannelHandlers();
// Step 5: Create and set local description (SDP offer)
const offer = await this.peerConnection.createOffer();
await this.peerConnection.setLocalDescription(offer);
// Step 6: Exchange SDP with HolySheep relay
const answer = await this.exchangeSDP(offer, credentials);
await this.peerConnection.setRemoteDescription(answer);
// Step 7: Complete ICE negotiation
await this.negotiate ICE();
this.isConnected = true;
console.log('[HolySheep] WebRTC connection established');
return this;
}
async getRelayCredentials() {
const response = await fetch(${HOLYSHEEP_BASE_URL}/webrtc/credentials, {
method: 'POST',
headers: {
'Authorization': Bearer ${this.apiKey},
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: this.model,
voice: 'alloy', // or 'echo', 'shimmer', 'coral', 'sage', 'ash'
instructions: 'You are a helpful AI assistant.'
})
});
if (!response.ok) {
throw new Error(HolySheep auth failed: ${response.status});
}
return response.json();
}
async exchangeSDP(offer, credentials) {
const response = await fetch(${HOLYSHEEP_BASE_URL}/webrtc/sdp, {
method: 'POST',
headers: {
'Authorization': Bearer ${this.apiKey},
'Content-Type': 'application/sdp'
},
body: offer.sdp
});
return {
type: 'answer',
sdp: await response.text()
};
}
setupDataChannelHandlers() {
this.dataChannel.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'transcript':
this.onTranscript(message.text, message.isFinal);
break;
case 'function_call':
this.onFunctionCall(message.name, message.arguments);
break;
case 'session_update':
console.log('[HolySheep] Session updated:', message.config);
break;
case 'error':
console.error('[HolySheep] API Error:', message.error);
break;
}
};
this.dataChannel.onopen = () => {
console.log('[HolySheep] Data channel open');
};
}
// Handle user microphone input
startAudioCapture() {
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(stream => {
const audioTracks = stream.getAudioTracks();
audioTracks.forEach(track => {
this.peerConnection.addTrack(track, stream);
});
// Apply noise suppression
const audioSource = this.audioContext.createMediaStreamSource(stream);
const analyser = this.audioContext.createAnalyser();
analyser.fftSize = 256;
audioSource.connect(analyser);
this.monitorAudioLevels(analyser);
console.log('[HolySheep] Audio capture started');
})
.catch(err => {
console.error('[HolySheep] Microphone access denied:', err);
});
}
monitorAudioLevels(analyser) {
const dataArray = new Uint8Array(analyser.frequencyBinCount);
const check = () => {
analyser.getByteFrequencyData(dataArray);
const average = dataArray.reduce((a, b) => a + b) / dataArray.length;
const normalized = average / 255;
if (normalized > this.vadThreshold) {
// Audio detected - send to HolySheep relay
this.sendAudioData(dataArray);
}
requestAnimationFrame(check);
};
check();
}
sendAudioData(audioBuffer) {
if (this.dataChannel && this.dataChannel.readyState === 'open') {
this.dataChannel.send(JSON.stringify({
type: 'input_audio_buffer_append',
audio: this.arrayBufferToBase64(audioBuffer)
}));
}
}
// Callback handlers - implement in your application
onTranscript(text, isFinal) {
console.log([Transcript${isFinal ? ' (final)' : ''}]: ${text});
}
onFunctionCall(name, arguments) {
console.log([Function Call]: ${name}, arguments);
}
disconnect() {
if (this.peerConnection) {
this.peerConnection.close();
}
this.isConnected = false;
console.log('[HolySheep] Disconnected');
}
// Utility functions
arrayBufferToBase64(buffer) {
// Implementation for audio data encoding
return btoa(String.fromCharCode.apply(null, buffer));
}
}
module.exports = HolySheepRealtimeVoice;
2. Building the Bidding抢答 System (Competitive Response Handler)
The "抢答" (competitive answering) scenario requires sub-100ms response validation. Here's how I implemented a race-condition-safe bidding system on top of HolySheep's infrastructure:
// bidding抢答-system.js
// Competitive response system with HolySheep AI
const HolySheepRealtimeVoice = require('./holy-sheep-webrtc-client');
class BiddingSystem {
constructor(config = {}) {
this.holySheep = new HolySheepRealtimeVoice({
apiKey: config.apiKey,
model: 'gpt-4o-realtime',
vadThreshold: 0.3, // Lower threshold for faster detection
vadSilenceTimeout: 300
});
this.bidders = new Map();
this.bidHistory = [];
this.auctionActive = false;
this.latencyMeasurements = [];
// Set up callbacks
this.holySheep.onTranscript = this.handleTranscript.bind(this);
}
async initialize() {
await this.holySheep.connect();
this.holySheep.startAudioCapture();
// Start latency monitoring
this.startLatencyMonitor();
console.log('[BiddingSystem] Initialized - HolySheep relay: <50ms overhead');
}
async startAuction(itemId, startingPrice, options = {}) {
this.auctionActive = true;
const auctionStart = Date.now();
const prompt = `
Auction item: ${itemId}
Starting price: $${startingPrice}
Rules: Respond to bids in under 100ms. Accept bids only when they exceed current price.
Current highest bidder gets priority in responses.
`;
// Send auction configuration to AI
this.sendSystemMessage(prompt);
return {
auctionId: auction_${Date.now()},
startTime: auctionStart,
status: 'active'
};
}
registerBidder(bidderId, displayName) {
this.bidders.set(bidderId, {
id: bidderId,
name: displayName,
currentBid: 0,
responseTimes: [],
joinTime: Date.now()
});
console.log([BiddingSystem] Bidder registered: ${displayName});
return this.bidders.get(bidderId);
}
handleTranscript(text, isFinal) {
if (!isFinal || !this.auctionActive) return;
const timestamp = Date.now();
// Extract bid amount using regex patterns
const bidPatterns = [
/\$?\s*(\d+(?:,\d{3})*(?:\.\d{2})?)/,
/(\d+(?:\.\d{2})?)\s*(?:dollars|USD)/i,
/bid\s*(?:of\s*)?\$?\s*(\d+)/i
];
for (const pattern of bidPatterns) {
const match = text.match(pattern);
if (match) {
const bidAmount = parseFloat(match[1].replace(',', ''));
this.processBid({
amount: bidAmount,
text: text,
timestamp: timestamp,
detectedLatency: timestamp - this.lastAudioTime
});
break;
}
}
}
processBid(bid) {
// Validate bid
if (bid.amount <= this.getCurrentHighestBid()) {
console.log([BiddingSystem] Bid rejected: $${bid.amount} <= current high);
return { accepted: false, reason: 'Below current bid' };
}
// Record latency for performance tracking
this.latencyMeasurements.push(bid.detectedLatency);
const averageLatency = this.latencyMeasurements.reduce((a, b) => a + b, 0) / this.latencyMeasurements.length;
console.log([BiddingSystem] Bid accepted: $${bid.amount} (latency: ${bid.detectedLatency}ms, avg: ${averageLatency.toFixed(1)}ms));
this.bidHistory.push({
...bid,
accepted: true,
averageLatency: averageLatency
});
return {
accepted: true,
bid: bid,
currentHigh: this.getCurrentHighestBid(),
holySheepLatency: '<50ms (HolySheep relay overhead)'
};
}
getCurrentHighestBid() {
if (this.bidHistory.length === 0) return 0;
return Math.max(...this.bidHistory.map(b => b.amount));
}
sendSystemMessage(content) {
if (this.holySheep.dataChannel?.readyState === 'open') {
this.holySheep.dataChannel.send(JSON.stringify({
type: 'conversation_item.create',
item: {
type: 'message',
role: 'system',
content: [{ type: 'input_text', text: content }]
}
}));
}
}
startLatencyMonitor() {
setInterval(() => {
if (this.latencyMeasurements.length > 0) {
const recent = this.latencyMeasurements.slice(-100);
const avg = recent.reduce((a, b) => a + b, 0) / recent.length;
const p95 = recent.sort((a, b) => a - b)[Math.floor(recent.length * 0.95)];
console.log([Latency Monitor] Avg: ${avg.toFixed(1)}ms, P95: ${p95}ms);
}
}, 5000);
}
getPerformanceStats() {
return {
totalBids: this.bidHistory.length,
averageLatency: this.latencyMeasurements.reduce((a, b) => a + b, 0) / this.latencyMeasurements.length,
p95Latency: this.latencyMeasurements.sort((a, b) => a - b)[Math.floor(this.latencyMeasurements.length * 0.95)],
holySheepSavings: '85%+ (¥1=$1 rate vs official ¥7.3)',
estimatedMonthlyCost: this.calculateMonthlyCost()
};
}
calculateMonthlyCost() {
const bidsPerDay = 1000;
const daysPerMonth = 30;
const avgAudioDuration = 5; // seconds
const totalAudioMinutes = (bidsPerDay * daysPerMonth * avgAudioDuration) / 60;
// HolySheep rate: ¥1=$1
const holySheepCost = totalAudioMinutes * 0.006; // ~$0.006/min for GPT-4o
// Official rate comparison: ¥7.3 = ~$1
const officialCost = totalAudioMinutes * 0.046; // ~7.3x more expensive
return {
holySheep: holySheepCost.toFixed(2),
official: officialCost.toFixed(2),
savings: officialCost - holySheepCost
};
}
}
// Usage example
async function main() {
const biddingSystem = new BiddingSystem({
apiKey: process.env.HOLYSHEEP_API_KEY
});
await biddingSystem.initialize();
// Register bidders
biddingSystem.registerBidder('user_001', 'Alice');
biddingSystem.registerBidder('user_002', 'Bob');
// Start auction
const auction = await biddingSystem.startAuction('Vintage Watch #47', 100);
console.log('Auction started:', auction);
// After 60 seconds
setTimeout(() => {
const stats = biddingSystem.getPerformanceStats();
console.log('Performance Stats:', stats);
biddingSystem.holySheep.disconnect();
}, 60000);
}
main().catch(console.error);
3. Server-Side WebSocket Relay (Alternative to Browser WebRTC)
For server-side applications or environments without WebRTC support, HolySheep offers a WebSocket-based relay:
// holy-sheep-websocket-relay.js
// Server-side WebSocket relay for OpenAI Realtime API
const WebSocket = require('ws');
const https = require('https');
const HOLYSHEEP_WS_URL = 'wss://api.holysheep.ai/v1/realtime';
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY;
class HolySheepWebSocketRelay {
constructor(options = {}) {
this.apiKey = options.apiKey || HOLYSHEEP_API_KEY;
this.model = options.model || 'gpt-4o-realtime';
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.messageQueue = [];
}
connect() {
return new Promise((resolve, reject) => {
const headers = {
'Authorization': Bearer ${this.apiKey},
'X-Model': this.model,
'Upgrade': 'websocket'
};
// For Node.js environment with self-signed certs, use custom agent
const agent = new https.Agent({
rejectUnauthorized: false // Remove in production with valid certs
});
this.ws = new WebSocket(HOLYSHEEP_WS_URL, {
headers,
agent
});
this.ws.on('open', () => {
console.log('[HolySheep WS] Connected to relay');
this.reconnectAttempts = 0;
this.flushMessageQueue();
resolve();
});
this.ws.on('message', (data) => {
this.handleMessage(JSON.parse(data));
});
this.ws.on('error', (error) => {
console.error('[HolySheep WS] Error:', error.message);
reject(error);
});
this.ws.on('close', (code, reason) => {
console.log([HolySheep WS] Closed: ${code} - ${reason});
this.attemptReconnect();
});
});
}
handleMessage(message) {
switch (message.type) {
case 'session.created':
console.log('[HolySheep WS] Session created:', message.session.id);
break;
case 'session.updated':
console.log('[HolySheep WS] Session updated');
break;
case 'conversation.item.created':
if (message.item.type === 'message' && message.item.role === 'assistant') {
const content = message.item.content[0];
if (content.type === 'audio') {
this.playAudio(content.audio);
} else if (content.type === 'text') {
console.log('[AI Response]:', content.text);
}
}
break;
case 'input_audio_buffer.speech_started':
console.log('[HolySheep WS] Speech detected');
break;
case 'input_audio_buffer.speech_stopped':
console.log('[HolySheep WS] Speech ended');
break;
case 'rate_limits.updated':
console.log('[HolySheep WS] Rate limits:', message.rate_limits);
break;
case 'error':
console.error('[HolySheep WS] Server error:', message.error);
break;
}
}
sendAudioChunk(audioBase64) {
const message = {
type: 'input_audio_buffer.append',
audio: audioBase64
};
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
} else {
this.messageQueue.push(message);
}
}
commitAudioBuffer() {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));
}
}
createConversationItem(role, content) {
const message = {
type: 'conversation.item.create',
item: {
type: 'message',
role: role,
content: [{ type: 'input_text', text: content }]
}
};
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
}
}
requestResponse() {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: 'response.create' }));
}
}
flushMessageQueue() {
while (this.messageQueue.length > 0 && this.ws?.readyState === WebSocket.OPEN) {
const message = this.messageQueue.shift();
this.ws.send(JSON.stringify(message));
}
}
attemptReconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.error('[HolySheep WS] Max reconnection attempts reached');
return;
}
this.reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
console.log([HolySheep WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}));
setTimeout(() => {
this.connect().catch(console.error);
}, delay);
}
disconnect() {
if (this.ws) {
this.ws.close(1000, 'Client disconnect');
}
}
playAudio(audioBase64) {
// Implement audio playback based on your environment
// Example: Web Audio API, speaker package, or stream to client
console.log('[HolySheep WS] Playing audio response');
}
}
module.exports = HolySheepWebSocketRelay;
Use Cases: When This Architecture Shines
Low-Latency Voice Duplex (Real-Time Conversation)
- AI Sales Agents: Sub-300ms perceived response time for natural sales conversations
- Language Tutoring: Instant feedback on pronunciation with under 100ms turnaround
- Voice-first Customer Support: Handle 10x more conversations with AI assistance
- Real-time Translation: Near-simultaneous translation with HolySheep's <50ms relay overhead
Competitive Bidding抢答 Scenarios
- Live Auction Platforms: Handle hundreds of simultaneous bidders with fair ordering
- Flash Sales: Process 10,000+ bid submissions per second
- Game Show Apps: Rank players by actual response time with server-side validation
- Trading Bots: Voice-controlled trading with latency-insensitive AI processing
Who This Is For (and Who Should Look Elsewhere)
Perfect Fit
- Teams building voice AI applications with users in Asia-Pacific
- Applications requiring consistent sub-300ms response perception
- Teams needing WeChat/Alipay payment integration
- Developers wanting 85%+ cost savings on voice API calls
- Production systems requiring <50ms relay latency
Not the Best Fit
- Simple text-only chatbots (use REST API directly)
- Applications with users primarily in EU/NA without latency concerns
- Prototypes where API costs are not a concern
- Projects requiring direct OpenAI SLA guarantees (bypassing relay)
Pricing and ROI
| Metric | HolySheep AI | Direct OpenAI | Savings |
|---|---|---|---|
| Voice API Rate | ¥1 = $1 USD | ¥7.3 = $1 USD | 85%+ savings |
| GPT-4.1 (Output) | $8.00 / MTok | $8.00 / MTok | Same price + relay savings |
| Claude Sonnet 4.5 | $15.00 / MTok | $15.00 / MTok | Same price + relay savings |
| Gemini 2.5 Flash | $2.50 / MTok | $2.50 / MTok | Same price + relay savings |
| DeepSeek V3.2 | $0.42 / MTok | $0.42 / MTok | Lowest cost option |
| Monthly Minimum | $0 (free credits on signup) | $0 | HolySheep wins |
| Payment Methods | WeChat, Alipay, Stripe | Credit card only | More options |
ROI Calculator: Voice AI Application
For a typical voice AI application processing 100,000 voice minutes per month:
- HolySheep Cost: 100,000 min × $0.006/min = $600/month
- Official API Cost: 100,000 min × $0.044/min = $4,400/month
- Monthly Savings: $3,800 (86%)
- Annual Savings: $45,600
Why Choose HolySheep
- APAC-Optimized Infrastructure: Sub-50ms relay latency for users in China, Japan, Korea, and Southeast Asia
- Cost Efficiency: 85%+ savings through the ¥1=$1 rate, compared to official ¥7.3 pricing
- Local Payment Integration: WeChat Pay and Alipay for seamless transactions in Chinese market
- API Compatibility: Drop-in replacement for OpenAI Realtime API with minimal code changes
- Free Tier: Credits on signup to test without immediate cost commitment
- Multi-Model Access: GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2 at competitive rates
Common Errors and Fixes
Error 1: 401 Authentication Failed
Symptom: Error: HolySheep auth failed: 401 or authentication prompt loop
Cause: Invalid or expired API key, or key not properly configured in environment
// ❌ WRONG - Key not set
const apiKey = process.env.HOLYSHEEP_API_KEY; // undefined if not set
// ✅ CORRECT - Explicit fallback and validation
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY || 'YOUR_HOLYSHEEP_API_KEY';
if (!HOLYSHEEP_API_KEY || HOLYSHEEP_API_KEY === 'YOUR_HOLYSHEEP_API_KEY') {
throw new Error('HolySheep API key not configured. Get yours at https://www.holysheep.ai/register');
}
// Verify key format (should start with 'hss_' or similar prefix)
if (!HOLYSHEEP_API_KEY.startsWith('hss_')) {
console.warn('Warning: API key may not be in correct format');
}
Error 2: WebRTC ICE Connection Failed
Symptom: RTCPeerConnection failed to connect with ICE state showing "failed"
Cause: Firewall blocking UDP 3478/19302, NAT traversal issues, or incorrect STUN/TURN server configuration
// ❌ WRONG - Single STUN server, no fallback
const config = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
};
// ✅ CORRECT - Multiple STUN servers + TURN fallback
const config = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' },
// Add HolySheep's TURN server for reliability
{
urls: 'turn:turn.holysheep.ai:3478',
username: credentials.turnUsername,
credential: credentials.turnCredential
}
],
iceCandidatePoolSize: 10,
iceTransportPolicy: 'all' // 'relay' if TURN required
};
// Add ICE connection state monitoring
peerConnection.oniceconnectionstatechange = () => {
console.log('ICE State:', peerConnection.iceConnectionState);
if (peerConnection.iceConnectionState === 'failed') {
// Attempt ICE restart
peerConnection.restartIce();
}
};
Error 3: Audio Buffer Overflow / Underflow
Symptom: Choppy audio, gaps in AI responses, or "buffer overflow" warnings
Cause: Audio chunks arriving faster than they can be processed, or network jitter causing gaps
// ❌ WRONG - Direct streaming without buffering
this.ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: chunk }));
// ✅ CORRECT - Buffered streaming with flow control
class AudioBufferManager {
constructor(options = {}) {
this.bufferSize = options.bufferSize || 4096; // samples
this.maxBufferMs = options.maxBufferMs || 100; // max 100ms buffer
this.queue = [];
this.lastFlushTime = 0;
this.flushInterval = options.flushInterval || 50; // ms
}
addChunk(audioData) {
this.queue.push({
data: audioData,
timestamp: Date.now()
});
// Auto-flush if buffer exceeds time threshold
if (this.shouldFlush()) {
this.flush();
}
}
shouldFlush() {
if (this.queue.length === 0) return false;
const oldest = this.queue[0];
const newest = this.queue[this.queue.length - 1];
const bufferDuration = newest.timestamp - oldest.timestamp;
return this.queue.length >= 10 || bufferDuration >= this.maxBufferMs;
}
flush() {