## client.tts.connect()

Opens a persistent WebSocket connection for low-latency, real-time TTS streaming. Supports multiplexed concurrent streams over a single connection. Use one connection per conversation/user session. Defaults to `PCM_22050_16` output format.

### Connection Setup

```javascript
import UpliftAI from '@upliftai/sdk-js';
import { writeFileSync } from 'fs';

const client = new UpliftAI({
  apiKey: 'your-api-key',
});

const ws = await client.tts.connect();
console.log(`Connected! Session ID: ${ws.sessionId}`);

ws.on('error', (err) => console.error('WS Error:', err));
ws.on('close', (code, reason) => console.log(`WS Closed: ${code} ${reason}`));
```

### Single Stream

```javascript
const audioChunks: Buffer[] = [];

const stream = ws.stream({
  text: 'ویب ساکٹ سے سلام',
  voiceId: 'v_meklc281',
  outputFormat: 'PCM_22050_16',
});

for await (const event of stream) {
  switch (event.type) {
    case 'audio_start':
      console.log(`audio_start (requestId: ${event.requestId})`);
      break;
    case 'audio':
      audioChunks.push(event.audio);
      process.stdout.write(
        `\r  chunks: ${audioChunks.length}, bytes: ${audioChunks.reduce((s, c) => s + c.length, 0)}`
      );
      break;
    case 'audio_end':
      console.log(`\n  audio_end (requestId: ${event.requestId})`);
      break;
    case 'error':
      console.error(`  error: ${event.code} - ${event.message}`);
      break;
  }
}

const audio = Buffer.concat(audioChunks);
writeFileSync('output.pcm', audio);
```

### Real-time Voice Agent Pattern

Pipe LLM output sentence-by-sentence into the WebSocket for continuous speech:

```javascript
const ws = await client.tts.connect();

// LLM streams tokens -> your tokenizer emits complete sentences
for await (const sentence of tokenizeSentences(llmStream)) {
  const stream = ws.stream({ text: sentence, voiceId: 'v_meklc281' });

for await (const event of stream) {
    if (event.type === 'audio') player.write(event.audio);
  }
}

// User interrupts mid-response
ws.cancelAll(); // stops all in-flight audio immediately

ws.close();
```

### Concurrent Streams

Send multiple requests over the same connection — they are multiplexed and processed concurrently.

```javascript
const s1 = ws.stream({ text: 'پہلا جملہ', voiceId: 'v_meklc281' });
const s2 = ws.stream({ text: 'دوسرا جملہ', voiceId: 'v_meklc281' });

console.log(`Active streams: ${ws.activeStreams}`); // 2

async function consumeStream(s: AsyncIterable<TTSStreamEvent>, label: string) {
  const chunks: Buffer[] = [];
  for await (const event of s) {
    if (event.type === 'audio') chunks.push(event.audio);
  }
  const total = Buffer.concat(chunks);
  console.log(`  ${label}: ${total.length} bytes`);
  return total;
}

await Promise.all([
  consumeStream(s1, 'stream 1'),
  consumeStream(s2, 'stream 2'),
]);
```

### Cancel / Barge-in

Cancel in-flight streams when the user interrupts mid-response:

```javascript
ws.stream({ text: 'یہ جملہ منسوخ ہو جائے گا', voiceId: 'v_meklc281' });
ws.stream({ text: 'یہ بھی منسوخ ہو جائے گا', voiceId: 'v_meklc281' });

console.log(`Active streams before cancel: ${ws.activeStreams}`);

ws.cancelAll(); // stops all in-flight audio immediately

console.log(`Active streams after cancel: ${ws.activeStreams}`); // 0

ws.close();
```

### Stream Events

| Event        | Fields                        | Description               |
|--------------|-------------------------------|---------------------------|
| `audio_start`| `requestId`, `timestamp`     | Synthesis has started     |
| `audio`      | `requestId`, `sequence`, `audio` | Audio chunk (Buffer)     |
| `audio_end`  | `requestId`, `timestamp`     | Synthesis complete        |
| `error`      | `requestId`, `code`, `message` | Error occurred            |

### WebSocket Properties

| Property     | Type                | Description                          |
|--------------|---------------------|--------------------------------------|
| `activeStreams` | `number`        | Number of in-flight streams          |
| `readyState` | `string`           | `connecting` · `open` · `closing` · `closed` |
| `sessionId`  | `string`           | Current session identifier           |

### WebSocket Methods

| Method                | Description                                   |
|-----------------------|-----------------------------------------------|
| `stream(request)`     | Start a new TTS stream (returns async iterable) |
| `cancelAll()`        | Cancel all in-flight streams                   |
| `close()`            | Close the connection                           |
| `on('error', fn)`   | Listen for connection errors                   |
| `on('close', fn)`   | Listen for connection close                    |
