# ODIN Audio Sending Examples

This folder contains examples demonstrating how to send audio to an ODIN room using both the **high-level** and **low-level** APIs.

## Examples

| File | API Level | Description |
|------|-----------|-------------|
| `test-kiss-api.js` | **High-Level** | Simplified API - just call `media.sendMP3()` |
| `index.js` | **Low-Level** | Full control over audio transmission |

## Prerequisites

1. **ODIN Access Key**: Get one for free at [4Players ODIN](https://www.4players.io/odin/introduction/access-keys/)
2. **Audio File**: A sample `santa.mp3` is included for testing

## Configuration

Edit either script and replace the placeholder values:

```javascript
const accessKey = "__YOUR_ACCESS_KEY__";  // Your ODIN access key
const roomId = "__YOUR_ROOM_ID__";        // Room to send audio to
const userId = "AudioBot-123";            // Bot's user ID
```

To enable E2EE (must match other peers):

```javascript
const cipherPassword = "shared-secret";
```

---

## High-Level API (`test-kiss-api.js`)

The high-level API is the **recommended approach** for most use cases. It handles all the complexity automatically.

### Features
- **Automatic Setup**: Claims media ID, sends StartMedia RPC
- **Audio Decoding**: Supports MP3, WAV, and other formats
- **Precise Timing**: Streams audio in 20ms chunks with correct timing
- **Simple Interface**: One method call to send an entire file

### Running

```bash
cd tests/sending-audio
node test-kiss-api.js
```

### Code Example

```javascript
// Create room and wait for join
const room = client.createRoom(token);
await new Promise(resolve => room.onJoined(resolve));
room.join("https://gateway.odin.4players.io");

// Create audio stream
const media = room.createAudioStream(44100, 2);

// Send audio with one line!
await media.sendMP3('./music.mp3');

// Or send other formats
await media.sendWAV('./audio.wav');
await media.sendBuffer(audioBuffer);  // Decoded AudioBuffer

// Clean up
media.close();
```

---

## Low-Level API (`index.js`)

The low-level API provides **full control** over audio transmission. Use it when you need:

- Custom audio sources (microphone, synthesized audio, real-time processing)
- Dynamic sample rate or channel configuration
- Fine-grained timing control
- Integration with custom audio pipelines

### Running

```bash
cd tests/sending-audio
node index.js
```

### Workflow

1. **Join Room** and wait for `Joined` event
2. **Get Media ID** from `event.mediaIds`
3. **Create Audio Stream** with sample rate and channels
4. **Set Media ID** on the stream
5. **Send StartMedia RPC** to notify server
6. **Send Audio Data** in 20ms chunks
7. **Close** when done

### Code Example

```javascript
import { encode } from '@msgpack/msgpack';

room.onJoined(async (event) => {
    // Get media ID from the event
    const mediaId = event.mediaIds[0];
    
    // Create audio stream
    const media = room.createAudioStream(48000, 2);
    
    // Set the server-assigned media ID
    media.setMediaId(mediaId);
    
    // Notify server we're about to transmit
    const rpc = encode([0, 1, "StartMedia", {
        media_id: mediaId,
        properties: { kind: "audio" }
    }]);
    room.sendRpc(new Uint8Array(rpc));
    
    // Send audio in 20ms chunks
    const chunkMs = 20;
    const samplesPerChunk = Math.floor(48000 * chunkMs / 1000) * 2;
    
    for (const chunk of audioChunks) {
        media.sendAudioData(chunk);
        await sleep(chunkMs);
    }
    
    // Clean up
    media.close();
});
```

---

## Audio Format Requirements

### Input Audio
- **Formats**: MP3, WAV, OGG, FLAC (via audio-decode)
- **Sample Rate**: Any (encoder handles resampling)
- **Channels**: Mono or Stereo

### sendAudioData() Requirements
- **Type**: `Float32Array`
- **Range**: `-1.0` to `1.0`
- **Format**: Interleaved if stereo (L, R, L, R, ...)
- **Chunk Size**: 20ms worth of samples

---

## Comparison

| Feature | High-Level API | Low-Level API |
|---------|---------------|---------------|
| Setup Complexity | Automatic | Manual |
| Media ID Handling | Automatic | Manual |
| StartMedia RPC | Automatic | Manual |
| Timing | Automatic | Manual |
| Custom Sources | ❌ | ✅ |
| Real-time Audio | ❌ | ✅ |
| Audio Processing | ❌ | ✅ |

---

## Troubleshooting

### "No available media IDs" Error
Wait for the `Joined` event before sending audio. The SDK provides media IDs in this event.

### Audio Not Heard
1. Check E2EE password matches other peers
2. Verify you're in the same room
3. Check that other peers have their audio output enabled

### Audio Choppy
- Ensure 20ms timing is maintained
- Check network connection quality
- Monitor jitter stats with `room.getJitterStats(mediaId)`

---

## Related Examples

- [connection-test](../connection-test/) - Basic connection and events
- [audio-recording](../audio-recording/) - Record audio from peers