# WebRTC Translation Integration Guide

**Version:** 1.0  
**Last Updated:** January 13, 2026  
**Target Application:** MyVirtualSpace Livestream App (`~/public_html/livestream/myvirtualspace`)

---

## Table of Contents

1. [Overview](#overview)
2. [Why Migrate from HLS to WebRTC?](#why-migrate-from-hls-to-webrtc)
3. [Solution 1: Public WebRTC Consumer Endpoint](#solution-1-public-webrtc-consumer-endpoint)
4. [Solution 2: Embeddable WebRTC Player](#solution-2-embeddable-webrtc-player)
5. [Implementation Roadmap](#implementation-roadmap)
6. [Testing & Debugging](#testing--debugging)
7. [Troubleshooting](#troubleshooting)
8. [Performance Considerations](#performance-considerations)

---

## Overview

This document provides comprehensive guidance for integrating ultra-low latency WebRTC translation feeds into the MyVirtualSpace Livestream application, replacing the current HLS-based implementation.

### Current Architecture (HLS)
```
Translator → WebRTC → Backend → RTMP → CDN → HLS (.m3u8)
Latency: 3-6 seconds
```

### New Architecture (WebRTC Direct)
```
Translator → WebRTC → MediaSoup Server ← WebRTC ← External App
Latency: <500ms (6-12x faster)
```

### Available Solutions

| Feature | Solution 1: API Endpoint | Solution 2: Embeddable Player |
|---------|-------------------------|-------------------------------|
| **Integration Effort** | Medium (WebRTC implementation) | Easy (iframe embed) |
| **Latency** | <500ms | <500ms |
| **Customization** | Full control | Limited by iframe |
| **Browser Support** | Modern browsers with WebRTC | Modern browsers with WebRTC |
| **Best For** | Advanced integrations, native apps | Quick integration, CMS systems |

---

## Why Migrate from HLS to WebRTC?

### Performance Comparison

| Metric | HLS (Current) | WebRTC (New) | Improvement |
|--------|--------------|--------------|-------------|
| **Latency** | 3-6 seconds | <500ms | **6-12x faster** |
| **Buffering** | 3+ segments | Minimal | **Smoother playback** |
| **Scalability** | CDN-based | P2P + Server | **Better efficiency** |
| **Audio Quality** | AAC 128kbps | Opus 128kbps | **Better codec** |
| **Video Quality** | H.264 | VP8/H.264 | **Comparable** |

### Use Cases Benefiting Most
- **Live Q&A sessions** - Real-time interaction
- **Worship services** - Synchronized translation with visual cues
- **Educational lectures** - Immediate comprehension feedback
- **Corporate presentations** - Professional real-time communication

---

## Solution 1: Public WebRTC Consumer Endpoint

### Architecture Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                     Translation Backend                          │
│                  https://ministryprogs.tniglobal.org            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐         ┌──────────────┐                     │
│  │  Translator  │────────>│   MediaSoup  │                     │
│  │  (Producer)  │  WebRTC │  SFU Server  │                     │
│  └──────────────┘         └──────┬───────┘                     │
│                                   │                              │
│                                   │ Routes to consumers          │
│                                   ↓                              │
│                          ┌────────────────┐                     │
│                          │  Consumer API  │                     │
│                          │   (Public)     │                     │
│                          └────────┬───────┘                     │
└───────────────────────────────────┼─────────────────────────────┘
                                    │
                                    │ WebRTC Connection
                                    ↓
                    ┌───────────────────────────────┐
                    │   MyVirtualSpace App          │
                    │   (Your Livestream Portal)    │
                    └───────────────────────────────┘
```

### API Endpoints

#### 1. Get Router RTP Capabilities (Public)

**Endpoint:** `GET /webrtc/public/router-capabilities`

**Description:** Retrieves the MediaSoup router's RTP capabilities needed for WebRTC connection.

**Request:**
```http
GET https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities
Content-Type: application/json
```

**Response:**
```json
{
  "rtpCapabilities": {
    "codecs": [
      {
        "kind": "audio",
        "mimeType": "audio/opus",
        "clockRate": 48000,
        "channels": 2
      },
      {
        "kind": "video",
        "mimeType": "video/VP8",
        "clockRate": 90000
      }
    ],
    "headerExtensions": [...]
  }
}
```

**Usage:**
```javascript
const response = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities');
const { rtpCapabilities } = await response.json();
```

---

#### 2. Create Consumer Transport (Public)

**Endpoint:** `POST /webrtc/public/create-consumer-transport`

**Description:** Creates a WebRTC transport for consuming media from a translator.

**Request:**
```http
POST https://ministryprogs.tniglobal.org/webrtc/public/create-consumer-transport
Content-Type: application/json

{
  "translatorId": "69075dfdd06430e3c53cff74",
  "language": "german"
}
```

**Parameters:**
- `translatorId` (string, required): MongoDB ObjectId of the translator
- `language` (string, required): Translation language (e.g., "german", "spanish", "french")

**Response:**
```json
{
  "transportId": "8f3a2e1c-9d7b-4f5e-a3c8-6b2d4e8f1a9c",
  "iceParameters": {
    "iceLite": true,
    "usernameFragment": "1a2b3c4d",
    "password": "5e6f7g8h9i0j"
  },
  "iceCandidates": [
    {
      "foundation": "udpcandidate",
      "priority": 1076302079,
      "ip": "123.45.67.89",
      "protocol": "udp",
      "port": 44444,
      "type": "host"
    }
  ],
  "dtlsParameters": {
    "role": "auto",
    "fingerprints": [
      {
        "algorithm": "sha-256",
        "value": "A1:B2:C3:D4:E5:F6:..."
      }
    ]
  }
}
```

---

#### 3. Connect Consumer Transport (Public)

**Endpoint:** `POST /webrtc/public/connect-consumer-transport`

**Description:** Completes the connection by providing DTLS parameters.

**Request:**
```http
POST https://ministryprogs.tniglobal.org/webrtc/public/connect-consumer-transport
Content-Type: application/json

{
  "transportId": "8f3a2e1c-9d7b-4f5e-a3c8-6b2d4e8f1a9c",
  "dtlsParameters": {
    "role": "client",
    "fingerprints": [
      {
        "algorithm": "sha-256",
        "value": "X1:Y2:Z3:..."
      }
    ]
  }
}
```

**Response:**
```json
{
  "success": true
}
```

---

#### 4. Consume Media (Public)

**Endpoint:** `POST /webrtc/public/consume`

**Description:** Starts consuming audio and video from the translator.

**Request:**
```http
POST https://ministryprogs.tniglobal.org/webrtc/public/consume
Content-Type: application/json

{
  "transportId": "8f3a2e1c-9d7b-4f5e-a3c8-6b2d4e8f1a9c",
  "translatorId": "69075dfdd06430e3c53cff74",
  "rtpCapabilities": { ... }
}
```

**Response:**
```json
{
  "consumers": [
    {
      "id": "video-consumer-id",
      "producerId": "video-producer-id",
      "kind": "video",
      "rtpParameters": { ... }
    },
    {
      "id": "audio-consumer-id",
      "producerId": "audio-producer-id",
      "kind": "audio",
      "rtpParameters": { ... }
    }
  ]
}
```

---

#### 5. Get Active Translators (Public)

**Endpoint:** `GET /webrtc/public/active-translators`

**Description:** Lists all currently translating users.

**Request:**
```http
GET https://ministryprogs.tniglobal.org/webrtc/public/active-translators
```

**Response:**
```json
{
  "translators": [
    {
      "id": "69075dfdd06430e3c53cff74",
      "fullName": "John Smith",
      "language": "german",
      "languageLabel": "German",
      "country": "Germany",
      "profileImage": "data:image/jpeg;base64,...",
      "isTranslating": true,
      "translationStartedAt": "2026-01-13T06:30:00.000Z"
    }
  ]
}
```

---

### Client-Side Implementation

#### Step 1: Install mediasoup-client

```bash
npm install mediasoup-client
```

#### Step 2: Create WebRTC Consumer Class

```javascript
// File: webrtc-consumer.js

import * as mediasoupClient from 'mediasoup-client';

class WebRTCConsumer {
  constructor() {
    this.device = null;
    this.consumerTransport = null;
    this.videoConsumer = null;
    this.audioConsumer = null;
    this.mediaStream = null;
  }

  /**
   * Initialize the WebRTC device
   */
  async initialize() {
    try {
      // Get router RTP capabilities
      const response = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities');
      const { rtpCapabilities } = await response.json();

      // Create device
      this.device = new mediasoupClient.Device();
      await this.device.load({ routerRtpCapabilities: rtpCapabilities });

      console.log('✅ WebRTC device loaded');
      return true;
    } catch (error) {
      console.error('Failed to initialize WebRTC device:', error);
      throw error;
    }
  }

  /**
   * Connect to translator's stream
   * @param {string} translatorId - MongoDB ObjectId of translator
   * @param {string} language - Translation language
   */
  async connectToTranslator(translatorId, language) {
    try {
      // Create consumer transport
      const transportResponse = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/create-consumer-transport', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ translatorId, language })
      });

      const { transportId, iceParameters, iceCandidates, dtlsParameters } = await transportResponse.json();

      // Create recv transport
      this.consumerTransport = this.device.createRecvTransport({
        id: transportId,
        iceParameters,
        iceCandidates,
        dtlsParameters
      });

      // Handle transport connection
      this.consumerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
        try {
          await fetch('https://ministryprogs.tniglobal.org/webrtc/public/connect-consumer-transport', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ transportId, dtlsParameters })
          });
          callback();
        } catch (error) {
          errback(error);
        }
      });

      // Consume media
      const consumeResponse = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/consume', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          transportId,
          translatorId,
          rtpCapabilities: this.device.rtpCapabilities
        })
      });

      const { consumers } = await consumeResponse.json();

      // Create media stream
      this.mediaStream = new MediaStream();

      // Consume each track (video and audio)
      for (const consumerData of consumers) {
        const consumer = await this.consumerTransport.consume({
          id: consumerData.id,
          producerId: consumerData.producerId,
          kind: consumerData.kind,
          rtpParameters: consumerData.rtpParameters
        });

        if (consumer.kind === 'video') {
          this.videoConsumer = consumer;
        } else if (consumer.kind === 'audio') {
          this.audioConsumer = consumer;
        }

        this.mediaStream.addTrack(consumer.track);
      }

      console.log('✅ Connected to translator stream');
      return this.mediaStream;
    } catch (error) {
      console.error('Failed to connect to translator:', error);
      throw error;
    }
  }

  /**
   * Disconnect and cleanup
   */
  disconnect() {
    if (this.videoConsumer) {
      this.videoConsumer.close();
      this.videoConsumer = null;
    }

    if (this.audioConsumer) {
      this.audioConsumer.close();
      this.audioConsumer = null;
    }

    if (this.consumerTransport) {
      this.consumerTransport.close();
      this.consumerTransport = null;
    }

    if (this.mediaStream) {
      this.mediaStream.getTracks().forEach(track => track.stop());
      this.mediaStream = null;
    }

    console.log('✅ Disconnected from translator stream');
  }
}

export default WebRTCConsumer;
```

#### Step 3: Use in Your Application

```javascript
// File: translation-player.js

import WebRTCConsumer from './webrtc-consumer.js';

class TranslationPlayer {
  constructor(videoElement) {
    this.videoElement = videoElement;
    this.consumer = new WebRTCConsumer();
  }

  async start(translatorId, language) {
    try {
      // Initialize WebRTC
      await this.consumer.initialize();

      // Connect to translator
      const stream = await this.consumer.connectToTranslator(translatorId, language);

      // Attach to video element
      this.videoElement.srcObject = stream;
      await this.videoElement.play();

      console.log('✅ Playing translation stream');
    } catch (error) {
      console.error('Failed to start translation:', error);
      throw error;
    }
  }

  stop() {
    this.consumer.disconnect();
    this.videoElement.srcObject = null;
  }
}

// Usage example
const videoElement = document.getElementById('translation-video');
const player = new TranslationPlayer(videoElement);

// Start playing German translation from specific translator
await player.start('69075dfdd06430e3c53cff74', 'german');

// Stop when done
player.stop();
```

#### Step 4: React/Vue Integration Example

**React Component:**

```jsx
import React, { useEffect, useRef, useState } from 'react';
import WebRTCConsumer from './webrtc-consumer';

function TranslationPlayer({ translatorId, language }) {
  const videoRef = useRef(null);
  const consumerRef = useRef(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let mounted = true;

    const startStream = async () => {
      try {
        setIsLoading(true);
        setError(null);

        // Initialize consumer
        consumerRef.current = new WebRTCConsumer();
        await consumerRef.current.initialize();

        // Connect to translator
        const stream = await consumerRef.current.connectToTranslator(translatorId, language);

        if (mounted && videoRef.current) {
          videoRef.current.srcObject = stream;
          await videoRef.current.play();
          setIsLoading(false);
        }
      } catch (err) {
        console.error('Stream error:', err);
        if (mounted) {
          setError(err.message);
          setIsLoading(false);
        }
      }
    };

    startStream();

    // Cleanup on unmount
    return () => {
      mounted = false;
      if (consumerRef.current) {
        consumerRef.current.disconnect();
      }
    };
  }, [translatorId, language]);

  return (
    <div className="translation-player">
      {isLoading && <div className="loading">Connecting to translator...</div>}
      {error && <div className="error">Error: {error}</div>}
      <video
        ref={videoRef}
        autoPlay
        playsInline
        controls
        style={{ width: '100%', height: 'auto' }}
      />
    </div>
  );
}

export default TranslationPlayer;
```

---

## Solution 2: Embeddable WebRTC Player

### Overview

This solution provides a ready-to-use player page that can be embedded via iframe. No WebRTC knowledge required!

### Player URL Format

```
https://programs.tniglobal.org/player/{translatorId}/{language}
```

**Example:**
```
https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german
```

### Embed in Your Application

#### Basic Iframe Embed

```html
<iframe 
  src="https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german"
  width="640"
  height="480"
  frameborder="0"
  allowfullscreen
  allow="autoplay; microphone; camera">
</iframe>
```

#### Responsive Embed (16:9 aspect ratio)

```html
<style>
  .video-container {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 aspect ratio */
    height: 0;
    overflow: hidden;
  }
  
  .video-container iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
</style>

<div class="video-container">
  <iframe 
    src="https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german"
    frameborder="0"
    allowfullscreen
    allow="autoplay; microphone; camera">
  </iframe>
</div>
```

#### Dynamic Language Selector

```html
<div class="translation-selector">
  <label>Select Translation Language:</label>
  <select id="language-select" onchange="changeTranslation()">
    <option value="german">German</option>
    <option value="spanish">Spanish</option>
    <option value="french">French</option>
    <option value="portuguese">Portuguese</option>
  </select>
</div>

<div class="video-container">
  <iframe 
    id="translation-iframe"
    src="https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german"
    frameborder="0"
    allowfullscreen
    allow="autoplay; microphone; camera">
  </iframe>
</div>

<script>
function changeTranslation() {
  const language = document.getElementById('language-select').value;
  const translatorId = '69075dfdd06430e3c53cff74'; // Get from your database
  const iframe = document.getElementById('translation-iframe');
  iframe.src = `https://programs.tniglobal.org/player/${translatorId}/${language}`;
}
</script>
```

#### WordPress Shortcode (If applicable)

```php
// Add to functions.php
function webrtc_translation_player_shortcode($atts) {
    $atts = shortcode_atts(array(
        'translator_id' => '',
        'language' => 'german',
        'width' => '100%',
        'height' => '480'
    ), $atts);

    $url = "https://programs.tniglobal.org/player/{$atts['translator_id']}/{$atts['language']}";
    
    return sprintf(
        '<iframe src="%s" width="%s" height="%s" frameborder="0" allowfullscreen allow="autoplay"></iframe>',
        esc_url($url),
        esc_attr($atts['width']),
        esc_attr($atts['height'])
    );
}
add_shortcode('translation_player', 'webrtc_translation_player_shortcode');

// Usage in WordPress:
// [translation_player translator_id="69075dfdd06430e3c53cff74" language="german"]
```

### Query Parameters (Optional)

Customize the player behavior with URL parameters:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `autoplay` | boolean | `true` | Auto-play when loaded |
| `controls` | boolean | `true` | Show video controls |
| `muted` | boolean | `false` | Start muted |
| `volume` | number | `1.0` | Initial volume (0.0-1.0) |

**Example:**
```
https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german?autoplay=false&muted=true&volume=0.5
```

### PostMessage API (Advanced)

The iframe player supports PostMessage for programmatic control:

```javascript
const iframe = document.getElementById('translation-iframe');

// Play
iframe.contentWindow.postMessage({ type: 'play' }, 'https://programs.tniglobal.org');

// Pause
iframe.contentWindow.postMessage({ type: 'pause' }, 'https://programs.tniglobal.org');

// Set volume (0.0 - 1.0)
iframe.contentWindow.postMessage({ type: 'volume', value: 0.8 }, 'https://programs.tniglobal.org');

// Mute
iframe.contentWindow.postMessage({ type: 'mute' }, 'https://programs.tniglobal.org');

// Unmute
iframe.contentWindow.postMessage({ type: 'unmute' }, 'https://programs.tniglobal.org');

// Listen for events from player
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://programs.tniglobal.org') return;
  
  switch (event.data.type) {
    case 'ready':
      console.log('Player is ready');
      break;
    case 'playing':
      console.log('Stream is playing');
      break;
    case 'error':
      console.error('Player error:', event.data.message);
      break;
  }
});
```

---

## Implementation Roadmap

### Phase 1: Preparation (Week 1)

#### Day 1-2: Environment Setup
- [ ] Review current MyVirtualSpace codebase
- [ ] Identify all HLS embed locations
- [ ] Document current translator ID mapping
- [ ] Set up development/staging environment

#### Day 3-5: API Testing
- [ ] Test public WebRTC endpoints from external domain
- [ ] Verify CORS configuration
- [ ] Test with different browsers (Chrome, Firefox, Safari, Edge)
- [ ] Measure latency and quality

### Phase 2: Solution 2 Implementation (Week 2)

**Recommended to start with Solution 2 (easier)**

#### Day 1-3: Basic Integration
- [ ] Replace HLS iframe embeds with WebRTC player iframes
- [ ] Update URL patterns: `m3u8` → `player/{id}/{language}`
- [ ] Test on staging environment
- [ ] Verify autoplay and controls work

#### Day 4-5: Advanced Features
- [ ] Implement language selector UI
- [ ] Add connection status indicators
- [ ] Implement error handling and fallbacks
- [ ] Add loading states

### Phase 3: Solution 1 Implementation (Week 3-4)

**For advanced use cases requiring full control**

#### Week 3: Core Implementation
- [ ] Install mediasoup-client dependency
- [ ] Create WebRTCConsumer class
- [ ] Implement connection logic
- [ ] Add to existing video player component

#### Week 4: Polish & Optimization
- [ ] Add reconnection logic
- [ ] Implement quality adaptive logic
- [ ] Add user preferences (volume, muted state)
- [ ] Performance optimization

### Phase 4: Testing & Launch (Week 5)

#### Testing Checklist
- [ ] Cross-browser testing (Chrome, Firefox, Safari, Edge)
- [ ] Mobile testing (iOS Safari, Android Chrome)
- [ ] Network conditions testing (3G, 4G, WiFi)
- [ ] Load testing (multiple concurrent viewers)
- [ ] Latency measurements

#### Launch
- [ ] Gradual rollout (10% → 50% → 100%)
- [ ] Monitor error rates
- [ ] Collect user feedback
- [ ] Document issues and solutions

---

## Testing & Debugging

### Testing Checklist

#### Basic Connectivity
```bash
# Test router capabilities
curl https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities

# Test active translators
curl https://ministryprogs.tniglobal.org/webrtc/public/active-translators
```

#### Browser Console Tests

```javascript
// Test WebRTC support
console.log('WebRTC supported:', !!window.RTCPeerConnection);

// Test device capabilities
navigator.mediaDevices.enumerateDevices().then(devices => {
  console.log('Available devices:', devices);
});

// Test connection to router
fetch('https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities')
  .then(res => res.json())
  .then(data => console.log('Router capabilities:', data))
  .catch(err => console.error('Connection failed:', err));
```

### Debug Logging

Enable verbose logging in your WebRTC consumer:

```javascript
class WebRTCConsumer {
  constructor(debug = false) {
    this.debug = debug;
    // ... rest of constructor
  }

  log(...args) {
    if (this.debug) {
      console.log('[WebRTC Consumer]', ...args);
    }
  }

  // Use throughout the class
  async initialize() {
    this.log('Initializing device...');
    // ... rest of method
  }
}

// Enable debug mode
const consumer = new WebRTCConsumer(true);
```

### Network Analysis

Use browser DevTools to analyze WebRTC traffic:

1. Open Chrome DevTools → `chrome://webrtc-internals`
2. Monitor ICE candidates, connection states
3. Check stats: bitrate, packets lost, jitter, RTT

---

## Troubleshooting

### Common Issues

#### Issue 1: "Failed to load router capabilities"

**Symptoms:** Cannot connect, 404 or CORS error

**Solutions:**
1. Verify endpoint URL is correct
2. Check CORS configuration on backend
3. Ensure firewall allows HTTPS traffic

```javascript
// Add error handling
try {
  const response = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/router-capabilities');
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }
  const data = await response.json();
} catch (error) {
  console.error('Failed to fetch capabilities:', error);
  // Implement fallback or retry logic
}
```

---

#### Issue 2: "No active translator found"

**Symptoms:** 404 error when trying to consume

**Solutions:**
1. Verify translator is actively translating
2. Check translator ID is correct MongoDB ObjectId
3. Ensure `isTranslating` flag is set

```javascript
// Check translator status first
async function checkTranslatorStatus(translatorId) {
  const response = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/active-translators');
  const { translators } = await response.json();
  
  const translator = translators.find(t => t.id === translatorId);
  if (!translator) {
    throw new Error('Translator not found or not translating');
  }
  
  return translator;
}
```

---

#### Issue 3: Black screen / No video

**Symptoms:** Connection successful but no video appears

**Solutions:**
1. Check video element `autoplay` attribute
2. Verify browser autoplay policies
3. Check if stream has video track

```javascript
// Debug stream tracks
if (mediaStream) {
  console.log('Audio tracks:', mediaStream.getAudioTracks().length);
  console.log('Video tracks:', mediaStream.getVideoTracks().length);
  
  mediaStream.getTracks().forEach(track => {
    console.log(`Track ${track.kind}:`, track.enabled, track.readyState);
  });
}

// Handle autoplay policy
videoElement.play().catch(error => {
  if (error.name === 'NotAllowedError') {
    console.warn('Autoplay blocked. User interaction required.');
    // Show play button for user to click
  }
});
```

---

#### Issue 4: High latency (>1 second)

**Symptoms:** Delay between translator and viewer

**Solutions:**
1. Check network RTT (Round Trip Time)
2. Verify server location proximity
3. Check for CPU throttling

```javascript
// Measure actual latency
const transport = this.consumerTransport;
const stats = await transport.getStats();

stats.forEach(report => {
  if (report.type === 'candidate-pair' && report.state === 'succeeded') {
    console.log('RTT (Round Trip Time):', report.currentRoundTripTime * 1000, 'ms');
  }
});
```

---

#### Issue 5: Audio/Video out of sync

**Symptoms:** Audio leads or lags video

**Solutions:**
1. Check if both consumers created successfully
2. Verify audio context sample rate
3. Implement audio sync adjustment

```javascript
// Check consumer creation
console.log('Video consumer:', this.videoConsumer?.id);
console.log('Audio consumer:', this.audioConsumer?.id);

// Both should be present for proper sync
if (!this.videoConsumer || !this.audioConsumer) {
  console.error('Missing consumer! Audio/video may not sync.');
}
```

---

## Performance Considerations

### Bandwidth Requirements

| Quality | Video Bitrate | Audio Bitrate | Total | Recommended Connection |
|---------|--------------|---------------|-------|------------------------|
| **Low** | 500 kbps | 64 kbps | 564 kbps | 3G (>1 Mbps) |
| **Medium** | 1000 kbps | 96 kbps | 1096 kbps | 4G (>2 Mbps) |
| **High** | 2500 kbps | 128 kbps | 2628 kbps | WiFi (>5 Mbps) |

### Scalability

**MediaSoup SFU Architecture:**
- Server CPU: ~2-5% per consumer (low overhead)
- Server Bandwidth: Full bitrate × number of consumers
- Recommended: Max 100 concurrent consumers per server instance

**Scaling Strategy:**
```
For 1000 concurrent viewers:
- Deploy 10 MediaSoup instances
- Use load balancer to distribute consumers
- Monitor CPU and bandwidth per instance
```

### Optimization Tips

1. **Lazy Loading:** Only connect when user clicks play
2. **Connection Pooling:** Reuse transports when switching languages
3. **Adaptive Quality:** Reduce bitrate on poor network
4. **Preload Check:** Test connection before showing player

```javascript
// Lazy load example
<button onclick="loadPlayer()">Watch Translation</button>

function loadPlayer() {
  // Only initialize WebRTC when user requests it
  const player = new TranslationPlayer(videoElement);
  await player.start(translatorId, language);
}
```

---

## Migration Strategy for MyVirtualSpace App

### Step-by-Step Migration

#### Current Code (HLS)
```html
<!-- Old HLS embed -->
<video id="translation-video" controls>
  <source src="https://tni-out.ceflixcdn.com/translations/german/playlist.m3u8" type="application/x-mpegURL">
</video>

<script>
  // Using hls.js for HLS playback
  if (Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource('https://tni-out.ceflixcdn.com/translations/german/playlist.m3u8');
    hls.attachMedia(video);
  }
</script>
```

#### New Code (WebRTC - Solution 2)
```html
<!-- New WebRTC embed (iframe) -->
<iframe 
  src="https://programs.tniglobal.org/player/69075dfdd06430e3c53cff74/german"
  width="100%"
  height="480"
  frameborder="0"
  allowfullscreen
  allow="autoplay">
</iframe>
```

#### New Code (WebRTC - Solution 1)
```html
<video id="translation-video" autoplay playsinline controls></video>

<script type="module">
  import WebRTCConsumer from './webrtc-consumer.js';
  
  const videoElement = document.getElementById('translation-video');
  const consumer = new WebRTCConsumer();
  
  await consumer.initialize();
  const stream = await consumer.connectToTranslator('69075dfdd06430e3c53cff74', 'german');
  videoElement.srcObject = stream;
</script>
```

### Data Mapping

**Map your existing translator data:**

```javascript
// Your existing database has M3U8 URLs like:
// "https://tni-out.ceflixcdn.com/translations/german/playlist.m3u8"

// Extract language from URL
const m3u8Url = "https://tni-out.ceflixcdn.com/translations/german/playlist.m3u8";
const language = m3u8Url.match(/translations\/(\w+)\//)[1]; // "german"

// Fetch translator by language from our API
const response = await fetch('https://ministryprogs.tniglobal.org/webrtc/public/active-translators');
const { translators } = await response.json();
const translator = translators.find(t => t.language === language);

// Use translator.id for WebRTC connection
const translatorId = translator.id; // "69075dfdd06430e3c53cff74"
```

---

## API Reference Summary

### Public Endpoints (No Authentication Required)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/webrtc/public/router-capabilities` | Get RTP capabilities |
| POST | `/webrtc/public/create-consumer-transport` | Create recv transport |
| POST | `/webrtc/public/connect-consumer-transport` | Connect transport |
| POST | `/webrtc/public/consume` | Start consuming media |
| GET | `/webrtc/public/active-translators` | List active translators |

### Player URL

```
https://programs.tniglobal.org/player/{translatorId}/{language}[?params]
```

---

## Support & Contact

### Backend Developer Contact
- **Server:** ministryprogs.tniglobal.org
- **WebRTC Port:** 3001
- **Protocol:** HTTPS/WSS

### CORS Configuration
The backend is configured to allow requests from:
- `https://programs.tniglobal.org` (Translation Frontend)
- `https://ministryprogs.tniglobal.org` (Backend Domain)
- `https://livestream.tniglobal.org` (MyVirtualSpace App) ✅
- Development: `localhost:3000`, `localhost:3003`, `localhost:3004`

**If you need to add another domain**, contact the backend team or update `server.js`:
```javascript
app.use(cors({
  origin: [
    'https://programs.tniglobal.org',
    'https://ministryprogs.tniglobal.org',
    'https://livestream.tniglobal.org',
    'https://your-new-domain.com',  // Add here
    // ...
  ],
  credentials: true
}));
```

### Useful Resources
- [MediaSoup Documentation](https://mediasoup.org/documentation/v3/)
- [WebRTC API Reference](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
- [mediasoup-client API](https://mediasoup.org/documentation/v3/mediasoup-client/api/)

### Testing Translator IDs

Use these translator IDs for testing:

```javascript
const testTranslators = [
  {
    id: "69075dfdd06430e3c53cff74",
    language: "german",
    name: "Test Translator - German"
  },
  {
    id: "[ASK FOR SPANISH ID]",
    language: "spanish", 
    name: "Test Translator - Spanish"
  }
];
```

---

## Conclusion

This integration guide provides two paths forward:

1. **Quick Start (Recommended):** Use Solution 2 (iframe embed) for immediate <500ms latency with minimal code changes
2. **Advanced Integration:** Use Solution 1 (API endpoint) for full control and native app integration

Both solutions eliminate the 3-6 second HLS delay, providing professional real-time translation experience for your users.

### Next Steps

1. Review this document with your development team
2. Set up a test environment
3. Choose Solution 2 for rapid deployment or Solution 1 for advanced features
4. Follow the implementation roadmap
5. Test thoroughly before production rollout

**Estimated Timeline:** 2-5 weeks depending on solution chosen and team resources.

---

**Document Version:** 1.0  
**Last Updated:** January 13, 2026  
**Prepared For:** MyVirtualSpace Development Team
