### Start Audio Streaming with User Media and Audio Context Setup Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This function initiates the audio streaming process. It validates user-provided configuration (token, server URL, sample rate, chunk size), requests microphone access using navigator.mediaDevices.getUserMedia, and creates an AudioContext with the specified sample rate. It then sets up the audio processor and starts intervals for sending batched audio and updating metrics. ```javascript async function startStreaming() { try { // Validate configuration config.token = document.getElementById('token').value.trim(); if (!config.token || config.token.length !== 64) { updateStatus('Invalid token: must be 64 hex characters', 'error'); return; } config.serverUrl = document.getElementById('serverUrl').value.trim(); config.sampleRate = parseInt(document.getElementById('sampleRate').value); config.chunkSize = parseInt(document.getElementById('chunkSize').value); updateStatus('Requesting microphone access...', 'idle'); log('Starting audio capture...'); // Get user media mediaStream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: config.channels, sampleRate: config.sampleRate, echoCancellation: true, noiseSuppression: true, autoGainControl: true } }); // Create audio context with specific sample rate audioContext = new AudioContext({ sampleRate: config.sampleRate }); updateStatus('Streaming audio...', 'running'); isStreaming = true; startTime = Date.now(); packetsSent = 0; bytesTransferred = 0; await createAudioProcessor(); // Start sending batched audio sendInterval = setInterval(sendBatchedAudio, config.sendIntervalMs); // Start metrics update setInterval(updateMetrics, 100); log('Audio streaming started', 'success'); } catch (error) { updateStatus(`Error: ${error.message}`, 'error'); log(`Error: ${error.message}`, 'error'); console.error(error); stopStreaming(); } } ``` -------------------------------- ### Starting Auxiliary Services with Docker Compose Source: https://context7.com/boilingdata/boilstream/llms.txt Command to start auxiliary services like Prometheus, Grafana, MinIO, and Superset using Docker Compose. Provides access URLs for each service after startup. ```bash # Start auxiliary services with docker-compose docker-compose up -d # Access monitoring interfaces # Grafana: http://localhost:3000 (admin/admin) # Prometheus: http://localhost:9090 # MinIO Console: http://localhost:9001 (minioadmin/minioadmin) # Superset: http://localhost:8088 (admin/admin) ``` -------------------------------- ### Initialize UI and Configuration Settings Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This code block initializes the application's UI status to 'Ready to start' and populates input fields with default configuration values for server URL, sample rate, and chunk size. This ensures a consistent starting state for the user. ```javascript // Initialize updateStatus('Ready to start', 'idle'); document.getElementById('serverUrl').value = config.serverUrl; document.getElementById('sampleRate').value = config.sampleRate; document.getElementById('chunkSize').value = config.chunkSize; ``` -------------------------------- ### Start BoilStream Server (Bash) Source: https://context7.com/boilingdata/boilstream/llms.txt Downloads and starts the BoilStream server binary. It can be run directly or via Docker. The server generates a configuration file if none is provided and exposes various interfaces for data ingestion and querying. Ensure to set the SERVER_IP_ADDRESS environment variable. ```bash # Download boilstream binaries (Linux: linux-x64, linux-aarch64 | macOS: darwin-x64, darwin-aarch64) curl -L -o boilstream https://www.boilstream.com/binaries/darwin-aarch64/boilstream-0.8.2 curl -L -o boilstream-admin https://www.boilstream.com/binaries/darwin-aarch64/boilstream-admin-0.8.2 chmod +x boilstream boilstream-admin # Start server with reachable IP address for Flight interface SERVER_IP_ADDRESS=1.2.3.4 ./boilstream # Docker deployment (x64-linux or aarch64-linux) docker run -v ./config.yaml:/app/config.yaml \ -p 443:443 -p 5432:5432 -p 50051:50051 -p 50250:50250 \ -e SERVER_IP_ADDRESS=1.2.3.4 boilinginsights/boilstream:aarch64-linux-0.8.2 ``` -------------------------------- ### DuckDB Interval Type Examples: SELECT statements Source: https://context7.com/boilingdata/boilstream/llms.txt This SQL code demonstrates the usage of the INTERVAL data type in DuckDB by selecting interval values. It shows examples of simple and complex interval specifications. ```sql SELECT INTERVAL '1 day 2 hours 30 minutes' as interval_example; SELECT INTERVAL '3 years 2 months 1 day' as complex_interval; ``` -------------------------------- ### Download and Execute BoilStream Binaries (Bash) Source: https://github.com/boilingdata/boilstream/blob/main/README.md This snippet demonstrates how to download the BoilStream and boilstream-admin binaries for macOS (aarch64 architecture) using curl and make them executable. It also shows how to start the BoilStream server, specifying the server IP address. ```bash # Download boilstream (generates example config if none provided) # Linux: linux-x64, linux-aarch64 | macOS: darwin-x64, darwin-aarch64 curl -L -o boilstream https://www.boilstream.com/binaries/darwin-aarch64/boilstream-0.8.2 curl -L -o boilstream-admin https://www.boilstream.com/binaries/darwin-aarch64/boilstream-admin-0.8.2 chmod +x boilstream boilstream-admin # SERVER_IP_ADDRESS is used on the Flight interface, use reachable IP address SERVER_IP_ADDRESS=1.2.3.4 ./boilstream ``` -------------------------------- ### DuckDB Data Type Examples: CREATE TABLE and INSERT statements Source: https://context7.com/boilingdata/boilstream/llms.txt This SQL code demonstrates the creation of tables with various complex DuckDB data types including BOOLEAN, BIGINT, UUID, JSON, LIST, STRUCT, MAP, and ENUM. It also shows how to insert sample data into these tables. ```sql CREATE SCHEMA IF NOT EXISTS demo; CREATE OR REPLACE TABLE demo.bool_samples(val BOOLEAN); INSERT INTO demo.bool_samples VALUES (TRUE),(FALSE),(TRUE),(FALSE); CREATE OR REPLACE TABLE demo.bigint_samples(val BIGINT); INSERT INTO demo.bigint_samples VALUES (-9223372036854775808),(0),(42),(9223372036854775807); CREATE OR REPLACE TABLE demo.uuid_samples(val UUID); INSERT INTO demo.uuid_samples VALUES ('00000000-0000-0000-0000-000000000000'), ('123e4567-e89b-12d3-a456-426614174000'), ('ffffffff-ffff-ffff-ffff-ffffffffffff'); CREATE OR REPLACE TABLE demo.json_samples(val JSON); INSERT INTO demo.json_samples VALUES ('null'::JSON), ('{"a":1,"b":[1,2,3]}'::JSON), ('{"nested":{"x":10,"y":[false, true]}}'::JSON); CREATE OR REPLACE TABLE demo.list_int_samples(val INT[]); INSERT INTO demo.list_int_samples VALUES ([ ]),([1]),([1,2,3]),([NULL]),([5,NULL,7]); CREATE OR REPLACE TABLE demo.struct_samples(val STRUCT(a INT, b VARCHAR, c BOOLEAN)); INSERT INTO demo.struct_samples VALUES ({a: 1, b: 'x', c: TRUE}), ({a: 42, b: 'meaning', c: TRUE}); CREATE OR REPLACE TABLE demo.map_samples(val MAP(VARCHAR, INT)); INSERT INTO demo.map_samples VALUES (map(['a'], [1])), (map(['x','y','z'], [1,2,3])); CREATE TYPE mood AS ENUM ('happy','sad','neutral','excited','tired'); CREATE OR REPLACE TABLE demo.enum_samples(val mood); INSERT INTO demo.enum_samples VALUES ('happy'),('sad'),('neutral'); ``` -------------------------------- ### Event Listeners for Start and Stop Streaming Buttons Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This section sets up event listeners for the 'Start Streaming' and 'Stop Streaming' buttons. Clicking 'Start Streaming' disables the start button, enables the stop button, and calls the `startStreaming` function. Clicking 'Stop Streaming' calls the `stopStreaming` function. ```javascript // Event handlers document.getElementById('startBtn').addEventListener('click', () => { document.getElementById('startBtn').disabled = true; document.getElementById('stopBtn').disabled = false; startStreaming(); }); document.getElementById('stopBtn').addEventListener('click', stopStreaming); ``` -------------------------------- ### Ingest Data into Streaming DuckLake (SQL) Source: https://github.com/boilingdata/boilstream/blob/main/README.md Shows how to ingest data into a streaming DuckLake using DuckDB clients. After the INSERT statement returns, the data is guaranteed to be on S3. This involves installing and loading the 'airport' extension and attaching the streaming DuckLake. ```sql INSTALL airport FROM community; LOAD airport; ATTACH 'my_data__stream' (TYPE AIRPORT, location 'grpc://localhost:50051/'); INSERT INTO my_data__stream.main.people SELECT 'user_' || i::VARCHAR AS name, (i % 100) + 1 AS age, ['duckdb'] AS tags FROM generate_series(1, 20000) as t(i); ``` -------------------------------- ### Ingesting NYC Taxi Data with BoilStream Source: https://context7.com/boilingdata/boilstream/llms.txt Example of ingesting the public NYC Yellow Taxi dataset through BoilStream. It includes schema definition, Parquet file ingestion from S3, and querying the ingested data. Requires the 'airport' extension. ```sql -- Install and load Airport extension INSTALL airport; LOAD airport; -- Create table with NYC Taxi schema CREATE TABLE boilstream.s3.nyc( VendorID INTEGER, tpep_pickup_datetime TIMESTAMP, tpep_dropoff_datetime TIMESTAMP, passenger_count BIGINT, trip_distance DOUBLE, RatecodeID BIGINT, store_and_fwd_flag VARCHAR, PULocationID INTEGER, DOLocationID INTEGER, payment_type BIGINT, fare_amount DOUBLE, extra DOUBLE, mta_tax DOUBLE, tip_amount DOUBLE, tolls_amount DOUBLE, improvement_surcharge DOUBLE, total_amount DOUBLE, congestion_surcharge DOUBLE, Airport_fee DOUBLE, cbd_congestion_fee DOUBLE ); -- Attach to BoilStream for writing ATTACH 'boilstream' AS data (TYPE AIRPORT, location 'grpc://localhost:50051/'); -- Ingest Parquet files from Internet INSERT INTO data.s3.nyc SELECT * FROM parquet_scan('yellow_tripdata_2025-*.parquet'); -- Query ingested data SELECT COUNT(*) FROM nyc; SELECT * FROM nyc ORDER BY passenger_count ASC LIMIT 10; ``` -------------------------------- ### Ingest Data via FlightRPC (SQL) Source: https://context7.com/boilingdata/boilstream/llms.txt Performs high-performance data ingestion using DuckDB's Airport extension over the FlightRPC protocol. Data is guaranteed to be persisted on S3 storage once the INSERT statement returns. This involves installing and loading the Airport extension, attaching to the BoilStream ingestion endpoint, and then inserting data. ```sql -- Install and load the Airport extension INSTALL airport FROM community; LOAD airport; -- Attach to BoilStream ingestion endpoint ATTACH 'my_data__stream' (TYPE AIRPORT, location 'grpc://localhost:50051/'); -- Ingest batch data - guaranteed on S3 when INSERT returns INSERT INTO my_data__stream.main.people SELECT 'user_' || i::VARCHAR AS name, (i % 100) + 1 AS age, ['duckdb'] AS tags FROM generate_series(1, 20000) as t(i); -- Large-scale ingestion example (6 million rows) INSERT INTO data.s3.people SELECT 'boilstream_' || i::VARCHAR as name, (i % 100) + 1 as age, ['airport', 'datasketches'] as tags FROM generate_series(1, 6000000) as t(i); -- Query ingested data SELECT COUNT(*) FROM people; SELECT COUNT(*), age FROM people GROUP BY age LIMIT 100; ``` -------------------------------- ### Create Streaming DuckLake and Views (SQL) Source: https://github.com/boilingdata/boilstream/blob/main/README.md Demonstrates how to create a streaming DuckLake with a '__stream' suffix. Tables within this DuckLake automatically become ingestion topics, and views are materialized as real-time streaming views. This is typically done via the Web GUI or the boilstream-admin CLI. ```sql -- Create streaming DuckLake (via Web GUI or boilstream-admin CLI) -- Tables in __stream DuckLakes automatically become ingestion topics CREATE TABLE my_data__stream.main.people (name VARCHAR, age INT, tags VARCHAR[]); -- Views become materialised real-time streaming views CREATE VIEW my_data__stream.main.adults AS SELECT * FROM people WHERE age > 50; ``` -------------------------------- ### Run BoilStream with Docker (Bash) Source: https://github.com/boilingdata/boilstream/blob/main/README.md This code snippet shows how to run BoilStream using Docker. It mounts a local configuration file, exposes necessary ports, and sets the SERVER_IP_ADDRESS environment variable. It specifies the Docker image for aarch64 Linux architecture. ```bash # Docker: boilinginsights/boilstream:x64-linux-0.8.2 or :aarch64-linux-0.8.2 docker run -v ./config.yaml:/app/config.yaml \ -p 443:443 -p 5432:5432 -p 50051:50051 -p 50250:50250 \ -e SERVER_IP_ADDRESS=1.2.3.4 boilinginsights/boilstream:aarch64-linux-0.8.2 ``` -------------------------------- ### Create and Configure Audio Worklet Processor for Audio Chunking Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This asynchronous function creates an AudioWorkletProcessor to handle audio chunking. It adds a JavaScript module to the audio context, defining a custom processor that buffers incoming audio samples and posts messages containing fixed-size chunks of samples and timestamps. This is crucial for preparing audio data for transmission. ```javascript async function createAudioProcessor() { await audioContext.audioWorklet.addModule(URL.createObjectURL(new Blob([ ` class AudioProcessor extends AudioWorkletProcessor { constructor() { super(); this.buffer = []; this.chunkSize = ${config.chunkSize}; } process(inputs, outputs) { const input = inputs[0]; if (input.length > 0) { const samples = input[0]; this.buffer.push(...samples); while (this.buffer.length >= this.chunkSize) { const chunk = this.buffer.slice(0, this.chunkSize); this.buffer = this.buffer.slice(this.chunkSize); this.port.postMessage({ samples: new Float32Array(chunk), timestamp: currentTime }); } } return true; } } registerProcessor('audio-processor', AudioProcessor); ` ], { type: 'application/javascript' }))); const source = audioContext.createMediaStreamSource(mediaStream); processor = new AudioWorkletNode(audioContext, 'audio-processor'); processor.port.onmessage = (event) => { // Buffer audio data audioBuffer.push(...event.data.samples); timestamps.push(event.data.timestamp); }; source.connect(processor); processor.connect(audioContext.destination); } ``` -------------------------------- ### Postgres Interface for BI Tools and DuckDB Catalog Source: https://context7.com/boilingdata/boilstream/llms.txt Connect BI tools like Power BI, DBeaver, and psql to query streaming data in real-time. Also serves as a DuckDB PostgreSQL catalog for native DuckDB clients. Supports various data types including UUIDs, decimals, arrays, timestamps, and JSON objects. ```sql -- Connect via psql or any Postgres client to port 5432 -- psql -h localhost -p 5432 -U your_user -d your_database -- Query streaming topic metadata SELECT * FROM boilstream.topics; SELECT * FROM boilstream.topic_schemas; SELECT * FROM boilstream.derived_views; -- Work with all DuckDB data types SELECT uuid() as uuid_v4, gen_random_uuid() as gen_uuid_v4, uuidv7() as uuid_v7; SELECT 12345.67::DECIMAL(22,2) as price, 0.00::DECIMAL(22,2) as zero, -999.99::DECIMAL(22,2) as negative; SELECT ['1aa', 'b2', 'c3', 'd4', 'z5'] as string_array; SELECT '2023-12-25 14:30:45'::TIMESTAMP as basic_timestamp, '2023-12-25 14:30:45.123456'::TIMESTAMP as timestamp_with_microseconds, '2023-12-25 14:30:45+02:00'::TIMESTAMPTZ as timestamp_with_tz, NOW() as current_timestamp; SELECT json_object('name', 'John', 'age', 30, 'city', 'New York') as json_obj; ``` -------------------------------- ### Grafana Provisioning for BoilStream Dashboards Source: https://context7.com/boilingdata/boilstream/llms.txt Configure Grafana to provision dashboards for visualizing BoilStream metrics. This YAML file specifies the dashboard provider, folder, and update interval. ```yaml # config/grafana/provisioning/dashboards/dashboard.yml avpiVersion: 1 providers: - name: 'BoilStream Dashboards' orgId: 1 folder: 'BoilStream' type: file disableDeletion: false updateIntervalSeconds: 10 allowUiUpdates: true options: path: /etc/grafana/provisioning/dashboards foldersFromFilesStructure: true ``` -------------------------------- ### JavaScript Audio Streaming with Flechette and Arrow Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html Implements the core logic for the Audio Arrow Streamer. It handles audio capture using the Web Audio API, batches audio data, serializes it into Apache Arrow format using the Flechette library, and sends it to a server. Includes functions for logging, updating status, and tracking metrics. ```javascript import * as fl from 'https://cdn.jsdelivr.net/npm/@uwdata/flechette@2.2.3/+esm'; let audioContext; let mediaStream; let processor; let isStreaming = false; let packetsSent = 0; let bytesTransferred = 0; let startTime; let sendInterval; // Configuration const config = { sampleRate: 16000, // GRCRN and Whisper optimal rate chunkSize: 16384, // Samples per chunk (1.024 seconds at 16kHz) channels: 1, // Mono audio serverUrl: 'https://localhost:8443', token: '', sendIntervalMs: 500 // Send batched data every 500ms }; // Audio buffer for batching let audioBuffer = []; let timestamps = []; function log(message, type = 'info') { const logDiv = document.getElementById('log'); const entry = document.createElement('div'); entry.className = `log-entry ${type}`; entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; logDiv.appendChild(entry); logDiv.scrollTop = logDiv.scrollHeight; } function updateStatus(message, type = 'idle') { const status = document.getElementById('status'); status.textContent = message; status.className = `status ${type}`; } function updateMetrics() { if (!isStreaming) return; const elapsed = (Date.now() - startTime) / 1000; document.getElementById('packets').textContent = packetsSent; document.getElementById('dataRate').textContent = ((bytesTransferred / 1024) / elapsed).toFixed(2) + ' KB/s'; document.getElementById('duration').textContent = elapsed.toFixed(1) + 's'; } async function sendBatchedAudio() { if (audioBuffer.length === 0) return; try { // Use Flechette to create proper Arrow table // Convert audio buffer to Float32Array const audioSamples = new Float32Array(audioBuffer); // Define explicit types to match server expectations const types = { audio_chunk: fl.list(fl.field('l', fl.float32())), // Variable-length list with named field timestamp_ms: fl.int64(), sample_rate: fl.int32() }; // Create a table with Flechette using explicit types const table = fl.tableFromArrays({ audio_chunk: [[...audioSamples]], // Nested array for List type timestamp_ms: [BigInt(Math.floor(timestamps[0] * 1000))], sample_rate: [config.sampleRate] }, { types }); console.log('Sending audio batch with', audioSamples.length, 'samples'); console.log('Table schema:', table.schema); // Convert to IPC stream format using Flechette const ipcStream = fl.tableToIPC(table, { format: 'stream' }); // Send via fetch const response = await fetch(`${config.serverUrl}/ingest/${config.token}`, { method: 'POST', headers: { 'Content-Type': 'application/vnd.apache.arrow.stream' }, body: ipcStream }); if (response.ok) { const result = await response.json(); packetsSent++; bytesTransferred += ipcStream.byteLength; log(`Sent batch: ${result.rows} rows, ${ipcStream.byteLength} bytes`, 'success'); } else if (response.status === 4 ``` -------------------------------- ### Prometheus Configuration for BoilStream Metrics Source: https://context7.com/boilingdata/boilstream/llms.txt Configure Prometheus to scrape BoilStream metrics. This YAML configuration sets the scrape interval and specifies the target for BoilStream metrics on port 8081. ```yaml # config/prometheus.yml global: scrape_interval: 1s evaluation_interval: 1s scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "boilstream" static_configs: - targets: ["host.docker.internal:8081"] metrics_path: /metrics scrape_interval: 1s ``` -------------------------------- ### HTML Structure for Audio Streamer Interface Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html Defines the basic HTML structure for the Audio Arrow Streamer, including elements for controls (start/stop buttons), status display, metrics, configuration, and a log area. This structure is essential for the JavaScript to interact with and update the user interface. ```html

Audio Arrow Streamer

Idle
0
Packets Sent
0.00
Data Rate (KB/s)
0.0s
Duration
``` -------------------------------- ### CSS Styling for Audio Streamer Interface Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html Provides the styling for the Audio Arrow Streamer web interface, defining the appearance of the body, container, buttons, status indicators, metrics, configuration inputs, and log output. It uses a dark theme with contrasting colors for readability and visual feedback. ```css body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background: #1a1a1a; color: #e0e0e0; } .container { background: #2a2a2a; padding: 30px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.3); } h1 { color: #4a9eff; margin-bottom: 30px; } .controls { display: flex; gap: 15px; margin-bottom: 30px; } button { padding: 12px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; transition: all 0.2s; font-weight: 600; } .start { background: #4a9eff; color: white; } .start:hover { background: #3a8eef; } .stop { background: #ff4a4a; color: white; } .stop:hover { background: #ef3a3a; } button:disabled { opacity: 0.5; cursor: not-allowed; } .status { padding: 15px; border-radius: 6px; margin-bottom: 20px; font-family: 'Courier New', monospace; } .status.idle { background: #333; color: #888; } .status.running { background: #1a4a1a; color: #4aff4a; } .status.error { background: #4a1a1a; color: #ff4a4a; } .metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 20px; } .metric { background: #333; padding: 15px; border-radius: 6px; text-align: center; } .metric-value { font-size: 24px; font-weight: bold; color: #4a9eff; } .metric-label { font-size: 14px; color: #888; margin-top: 5px; } .config { margin-bottom: 20px; padding: 15px; background: #333; border-radius: 6px; } .config-item { margin-bottom: 10px; } .config-item label { display: inline-block; width: 150px; color: #aaa; } .config-item input { padding: 5px; background: #444; border: 1px solid #555; color: #fff; border-radius: 4px; } .config-item input[type="number"] { width: 100px; } .config-item input[type="text"] { width: 400px; font-family: 'Courier New', monospace; font-size: 12px; } .config-item input[type="url"] { width: 300px; } .log { background: #1a1a1a; padding: 15px; border-radius: 6px; max-height: 200px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px; margin-top: 20px; } .log-entry { margin-bottom: 5px; color: #888; } .log-entry.error { color: #ff4a4a; } .log-entry.success { color: #4aff4a; } ``` -------------------------------- ### HTTP/2 Arrow Ingestion (JavaScript) Source: https://context7.com/boilingdata/boilstream/llms.txt Streams Apache Arrow data from browsers or HTTP clients using Flechette.js. This method supports tens of thousands of concurrent connections and includes rate limiting. The process involves creating an Arrow table, converting it to an IPC stream format, and sending it via HTTPS. ```javascript import * as fl from 'https://cdn.jsdelivr.net/npm/@uwdata/flechette@2.2.3/+esm'; // Create Arrow table with audio data example const types = { audio_chunk: fl.list(fl.field('l', fl.float32())), timestamp_ms: fl.int64(), sample_rate: fl.int32() }; const table = fl.tableFromArrays({ audio_chunk: [[...audioSamples]], timestamp_ms: [BigInt(Math.floor(Date.now()))], sample_rate: [16000] }, { types }); // Convert to IPC stream format const ipcStream = fl.tableToIPC(table, { format: 'stream' }); // Send via HTTPS (port 443) const response = await fetch(`https://localhost:8443/ingest/${token}`, { method: 'POST', headers: { 'Content-Type': 'application/vnd.apache.arrow.stream' }, body: ipcStream }); // Handle response if (response.ok) { const result = await response.json(); console.log(`Sent batch: ${result.rows} rows`); } else if (response.status === 429) { const retryAfter = response.headers.get('x-retry-after-ms') || '1000'; console.log(`Rate limited, retry after ${retryAfter}ms`); } ``` -------------------------------- ### Handle Rate Limiting and Server Errors in Audio Streaming Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This function handles responses from the server, specifically checking for rate limiting ('x-retry-after-ms' header) and other server-side errors. It logs errors, retries sending data after a specified delay, or logs general server errors. It clears audio buffers only on successful sends. ```javascript async function sendBatchedAudio() { if (audioBuffer.length === 0) return; try { const response = await fetch(config.serverUrl + '/audio', { method: 'POST', headers: { 'Authorization': `Bearer ${config.token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ samples: audioBuffer, timestamps: timestamps }) }); if (!response.ok) { if (response.status === 429) { // Rate limited const retryAfter = response.headers.get('x-retry-after-ms') || '1000'; log(`Rate limited, retry after ${retryAfter}ms`, 'error'); setTimeout(() => sendBatchedAudio(), parseInt(retryAfter)); return; // Don't clear buffer, retry later } else { const error = await response.json(); log(`Server error: ${error.error}`, 'error'); } } else { // Clear buffers after successful send audioBuffer = []; timestamps = []; packetsSent++; bytesTransferred += new TextEncoder().encode(JSON.stringify({ samples: audioBuffer, timestamps: timestamps })).length; } } catch (error) { log(`Send error: ${error.message}`, 'error'); updateStatus(`Error: ${error.message}`, 'error'); } } ``` -------------------------------- ### Stop Audio Streaming and Clean Up Resources Source: https://github.com/boilingdata/boilstream/blob/main/audio-arrow-streamer.html This function gracefully stops the audio streaming process. It sets the streaming flag to false, clears any active intervals for sending audio and updating metrics, disconnects the audio processor, closes the audio context, and stops all tracks from the media stream. It also resets buffer arrays and updates the UI status. ```javascript function stopStreaming() { isStreaming = false; if (sendInterval) { clearInterval(sendInterval); sendInterval = null; } if (processor) { processor.disconnect(); processor = null; } if (audioContext) { audioContext.close(); audioContext = null; } if (mediaStream) { mediaStream.getTracks().forEach(track => track.stop()); mediaStream = null; } // Clear buffers audioBuffer = []; timestamps = []; updateStatus('Stopped', 'idle'); document.getElementById('startBtn').disabled = false; document.getElementById('stopBtn').disabled = true; log('Audio streaming stopped'); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.