Player Integration

Complete guide to integrate Stream API with video players. Supports Widevine DRM.

Note: Widevine DRM requires HTTPS and a supported browser (Chrome, Firefox, Edge).

Supported Players

Shaka Player
Recommended

Google's open-source player with excellent DRM support.

Video.js

Popular player with EME plugin for DRM.

ExoPlayer

Android native player with Widevine support.

Integration Examples

1. Include Shaka Player

html
<script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.7.11/shaka-player.compiled.min.js"></script>
<video id="video" width="100%" controls></video>

2. Initialize Player

javascript
const API_URL = 'https://stream-api-production-f4f7.up.railway.app';
const API_KEY = 'YOUR_API_KEY';

async function playChannel(epgId, channelId) {
  // 1. Get stream data from API
  const response = await fetch(
    `${API_URL}/api/stream/${epgId}?ch=${channelId}`,
    { headers: { 'X-API-Key': API_KEY } }
  );
  const data = await response.json();

  // 2. Initialize Shaka Player
  const video = document.getElementById('video');
  const player = new shaka.Player(video);

  // 3. Configure DRM
  player.configure({
    drm: {
      servers: {
        'com.widevine.alpha': data.drm.server
      },
      advanced: {
        'com.widevine.alpha': {
          headers: data.drm.headers
        }
      }
    }
  });

  // 4. Handle errors
  player.addEventListener('error', (e) => {
    console.error('Player error:', e.detail);
  });

  // 5. Load and play
  await player.load(data.manifest);
  video.play();
}

3. Complete HTML Example

html
<!DOCTYPE html>
<html>
<head>
  <title>Stream Player</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.7.11/shaka-player.compiled.min.js"></script>
  <style>
    video { width: 100%; max-width: 800px; }
  </style>
</head>
<body>
  <video id="video" controls></video>
  <script>
    const API_URL = 'https://stream-api-production-f4f7.up.railway.app';
    const API_KEY = 'YOUR_API_KEY';

    async function init() {
      // Get channels
      const channels = await fetch(`${API_URL}/api/channels`, {
        headers: { 'X-API-Key': API_KEY }
      }).then(r => r.json());

      // Play first live channel
      const channel = channels.live[0];
      if (channel) {
        playChannel(channel.epgId, channel.channelId);
      }
    }

    async function playChannel(epgId, channelId) {
      const data = await fetch(
        `${API_URL}/api/stream/${epgId}?ch=${channelId}`,
        { headers: { 'X-API-Key': API_KEY } }
      ).then(r => r.json());

      const player = new shaka.Player(document.getElementById('video'));
      player.configure({
        drm: {
          servers: { 'com.widevine.alpha': data.drm.server },
          advanced: { 'com.widevine.alpha': { headers: data.drm.headers } }
        }
      });
      await player.load(data.manifest);
    }

    init();
  </script>
</body>
</html>

Error Handling

javascript
player.addEventListener('error', (event) => {
  const error = event.detail;
  
  switch (error.code) {
    case shaka.util.Error.Code.LICENSE_REQUEST_FAILED:
      console.error('DRM license request failed');
      // Refresh stream data and retry
      break;
    case shaka.util.Error.Code.LOAD_INTERRUPTED:
      console.error('Stream loading interrupted');
      break;
    default:
      console.error('Player error:', error.message);
  }
});

Auto Token Refresh

Stream tokens expire after ~1 hour. Implement auto-refresh for long viewing sessions:

javascript
let refreshInterval;

async function startStream(epgId, channelId) {
  await playChannel(epgId, channelId);
  
  // Refresh every 15 minutes
  refreshInterval = setInterval(async () => {
    const currentTime = player.getMediaElement().currentTime;
    await playChannel(epgId, channelId);
    player.getMediaElement().currentTime = currentTime;
  }, 15 * 60 * 1000);
}

function stopStream() {
  clearInterval(refreshInterval);
  player.unload();
}