Key Points
URL Parameters:sampleRate(default: 16000)noiseSuppression(0/1)gainControl(0/1)backgroundVoiceSuppression(0/1)
- Backend: Bearer token in the
Authorizationheader - Frontend: API key in the first message
Backend to Backend
const WebSocket = require('ws');
const fs = require('fs');
const wav = require('wav');
const AudioContext = require('web-audio-api').AudioContext;
const audioContext = new AudioContext();
// Connection parameters
const uri = 'wss://api-dev.meeamitech.com/audio/v1/uploads/stream?sampleRate=16000&noiseSuppression=1&gainControl=1&backgroundVoiceSuppression=1';
const apiKey = 'YOUR_API_KEY';
class AudioClient {
constructor() {
this.ws = new WebSocket(uri, {
headers: {
'Authorization': `Bearer ${apiKey}`
}
});
this.setupWebSocket();
}
setupWebSocket() {
this.ws.on('open', () => {
console.log('Connected to WebSocket server');
});
this.ws.on('message', (data) => {
console.log('Received processed audio chunk:', data.length, 'bytes');
// Handle processed audio...
});
this.ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
this.ws.on('close', () => {
console.log('Connection closed');
});
}
// Example 1: Send raw PCM data
sendRawPCM() {
const audioBuffer = fs.readFileSync('input.raw');
this.sendInChunks(audioBuffer);
}
// Example 2: Send WAV file
sendWavFile() {
const reader = new wav.Reader();
const readStream = fs.createReadStream('input.wav');
reader.on('format', format => {
console.log('WAV format:', format);
});
reader.on('data', (chunk) => {
this.sendInChunks(chunk);
});
readStream.pipe(reader);
}
// Example 3: Send audio buffer
async sendAudioFile(filePath) {
const audioData = fs.readFileSync(filePath);
const audioBuffer = await audioContext.decodeAudioData(audioData.buffer);
const pcmData = this.convertToInt16(audioBuffer);
this.sendInChunks(pcmData);
}
sendInChunks(buffer) {
const chunkSize = 640; // 320 samples * 2 bytes
let offset = 0;
const sendChunk = () => {
if (offset >= buffer.length) {
return;
}
const chunk = buffer.slice(offset, offset + chunkSize);
this.ws.send(chunk);
offset += chunkSize;
setTimeout(sendChunk, 20);
};
sendChunk();
}
convertToInt16(audioBuffer) {
const samples = audioBuffer.getChannelData(0);
const int16Array = new Int16Array(samples.length);
for (let i = 0; i < samples.length; i++) {
int16Array[i] = samples[i] * 32767;
}
return Buffer.from(int16Array.buffer);
}
}
// Usage
const client = new AudioClient();
client.sendWavFile();
// or client.sendAudioFile('input.mp3');
// or client.sendRawPCM();
# Backend WebSocket Client (Python)
import asyncio
import websockets
import numpy as np
from scipy.io import wavfile
import soundfile as sf
async def send_audio_data():
# Connection parameters
uri = "wss://api-dev.meeamitech.com/audio/v1/uploads/stream?sampleRate=16000&noiseSuppression=1&gainControl=1&backgroundVoiceSuppression=1"
api_key = "YOUR_API_KEY" # Replace with your actual API key
headers = {
"Authorization": f"Bearer {api_key}"
}
async with websockets.connect(uri, extra_headers=headers) as websocket:
# Example 1: Send synthetic audio data
sample_rate = 16000
duration = 1 # seconds
t = np.linspace(0, duration, sample_rate * duration)
audio_data = (np.sin(2 * np.pi * 440 * t) * 32767).astype(np.int16)
# Example 2: Read from WAV file
sample_rate, wav_data = wavfile.read('input.wav')
audio_data = wav_data.astype(np.int16)
# Example 3: Read from other audio formats using soundfile
audio_data, sample_rate = sf.read('input.mp3')
audio_data = (audio_data * 32767).astype(np.int16) # Normalize and convert to int16
# Send audio data in chunks
chunk_size = 320 # matches server's framesz
for i in range(0, len(audio_data), chunk_size):
chunk = audio_data[i:i + chunk_size]
await websocket.send(chunk.tobytes())
# Receive and process the audio
processed_audio = await websocket.recv()
processed_chunk = np.frombuffer(processed_audio, dtype=np.int16)
# Do something with processed_chunk...
# Run the client
if __name__ == "__main__":
asyncio.run(send_audio_data())
asyncio.run(connect_to_server())
import javax.sound.sampled.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@ClientEndpoint
public class AudioWebSocketClient {
private static final String URI = "wss://api-dev.meeamitech.com/audio/v1/uploads/stream?sampleRate=16000&noiseSuppression=1&gainControl=1&backgroundVoiceSuppression=1";
private static final String API_KEY = "YOUR_API_KEY";
private Session session;
private final BlockingQueue<byte[]> audioQueue = new LinkedBlockingQueue<>();
// Example 1: Send microphone input
public void startMicrophoneCapture() {
try {
AudioFormat format = new AudioFormat(16000, 16, 1, true, true);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException("Line not supported");
}
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
Thread captureThread = new Thread(() -> {
byte[] buffer = new byte[640];
while (true) {
int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
audioQueue.offer(buffer.clone());
}
}
});
captureThread.start();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
// Example 2: Send WAV file
public void sendWavFile(String filePath) {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(filePath));
AudioFormat format = audioInputStream.getFormat();
// Convert to required format if necessary
if (!format.matches(new AudioFormat(16000, 16, 1, true, true))) {
AudioFormat targetFormat = new AudioFormat(16000, 16, 1, true, true);
audioInputStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream);
}
byte[] buffer = new byte[640];
int bytesRead;
while ((bytesRead = audioInputStream.read(buffer)) != -1) {
if (session.isOpen()) {
session.getBasicRemote().sendBinary(ByteBuffer.wrap(buffer, 0, bytesRead));
Thread.sleep(20);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Example 3: Send synthetic audio
public void sendSyntheticAudio() {
try {
// Generate a 440Hz sine wave
double frequency = 440;
double sampleRate = 16000;
double amplitude = 32767;
double duration = 1.0; // seconds
int numSamples = (int) (sampleRate * duration);
ByteBuffer buffer = ByteBuffer.allocate(numSamples * 2);
buffer.order(ByteOrder.BIG_ENDIAN);
for (int i = 0; i < numSamples; i++) {
double time = i / sampleRate;
short sample = (short) (amplitude * Math.sin(2 * Math.PI * frequency * time));
buffer.putShort(sample);
}
byte[] audioData = buffer.array();
int chunkSize = 640;
for (int i = 0; i < audioData.length; i += chunkSize) {
int size = Math.min(chunkSize, audioData.length - i);
byte[] chunk = Arrays.copyOfRange(audioData, i, i + size);
session.getBasicRemote().sendBinary(ByteBuffer.wrap(chunk));
Thread.sleep(20);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(ByteBuffer message) {
byte[] processedAudio = new byte[message.remaining()];
message.get(processedAudio);
// Handle processed audio...
}
// Other methods (connect, onClose, etc.) remain the same...
}