Skip to content

Multi-CDN Setup

Lunar Stream provides multiple CDN endpoints for redundancy and optimal global performance.

Why Multi-CDN?

  • High Availability: If one CDN has issues, viewers automatically switch to another
  • Global Performance: Different CDNs may perform better in different regions
  • Load Distribution: Spread traffic across multiple providers

CDN Failover Flow

Available CDN Endpoints

Each livestream is available through multiple CDN providers:

CDNURL PatternCoverage
Primaryhttps://stream.lunarstream.kozow.com/live/{streamKey}/hls.m3u8Global
BunnyCDNhttps://zlmediakit-cdn.b-cdn.net/live/{streamKey}/hls.m3u8Global
Gcorehttps://gcore-zlmediakit.lunarstream.kozow.com/live/{streamKey}/hls.m3u8Global

Getting CDN URLs

When you retrieve a livestream, the response includes all available CDN URLs:

bash
curl -X GET "https://api.xxxxxx.xxx/api/v1/livestream/LIVESTREAM_ID?projectId=PROJECT_ID" \
  -H "ls-api-key: YOUR_API_KEY"

Response:

json
{
  "data": {
    "id": "d926da37-56ae-4212-83bc-f20d9de64d6b",
    "streamKey": "ee04affe2a669854052102fe762bd715",
    "hlsSources": [
      {
        "name": "origin",
        "url": "https://stream.lunarstream.kozow.com/hls/ee04affe2a669854052102fe762bd715/master.m3u8"
      },
      {
        "name": "bunny",
        "url": "https://bunny.lunarstream.kozow.com/hls/ee04affe2a669854052102fe762bd715/master.m3u8"
      },
      {
        "name": "gcore",
        "url": "https://gcore.lunarstream.kozow.com/hls/ee04affe2a669854052102fe762bd715/master.m3u8"
      }
    ]
  }
}

Implementing CDN Failover

JavaScript Implementation

javascript
class MultiCDNPlayer {
  constructor(hlsSources) {
    this.cdnUrls = hlsSources.map(s => s.url);
    this.currentIndex = 0;
  }

  getCurrentUrl() {
    return this.cdnUrls[this.currentIndex];
  }

  switchToNextCDN() {
    if (this.currentIndex < this.cdnUrls.length - 1) {
      this.currentIndex++;
      console.log(`Switching to CDN: ${this.getCurrentUrl()}`);
      return true;
    }
    return false;
  }

  reset() {
    this.currentIndex = 0;
  }
}

// Usage with Video.js
const cdnPlayer = new MultiCDNPlayer(hlsSources);
const player = videojs('video-player');

player.src({ src: cdnPlayer.getCurrentUrl(), type: 'application/x-mpegURL' });

player.on('error', () => {
  if (cdnPlayer.switchToNextCDN()) {
    player.src({ src: cdnPlayer.getCurrentUrl(), type: 'application/x-mpegURL' });
    player.play();
  } else {
    console.error('All CDNs failed');
  }
});

React Hook Implementation

javascript
import { useState, useCallback } from 'react';

function useMultiCDN(hlsSources) {
  const urls = hlsSources.map(s => s.url);
  const [currentIndex, setCurrentIndex] = useState(0);

  const currentUrl = urls[currentIndex];
  const hasMoreCDNs = currentIndex < urls.length - 1;

  const switchToNextCDN = useCallback(() => {
    if (hasMoreCDNs) {
      setCurrentIndex(prev => prev + 1);
      return true;
    }
    return false;
  }, [hasMoreCDNs]);

  const reset = useCallback(() => {
    setCurrentIndex(0);
  }, []);

  return { currentUrl, switchToNextCDN, reset, hasMoreCDNs };
}

// Usage
const StreamPlayer = ({ hlsSources }) => {
  const { currentUrl, switchToNextCDN } = useMultiCDN(hlsSources);

  const handleError = () => {
    if (!switchToNextCDN()) {
      console.error('All CDNs failed');
    }
  };

  return (
    <video src={currentUrl} onError={handleError} controls />
  );
};

Best Practices

1. Region-Based CDN Selection

Prioritize CDNs based on viewer location for optimal performance:

javascript
function selectOptimalCDN(hlsSources, userRegion) {
  const cdnPriority = {
    'asia': ['gcore', 'bunny', 'origin'],
    'europe': ['bunny', 'gcore', 'origin'],
    'americas': ['bunny', 'origin', 'gcore'],
    'default': ['origin', 'bunny', 'gcore']
  };

  const priority = cdnPriority[userRegion] || cdnPriority['default'];

  return hlsSources.sort((a, b) => {
    const aIndex = priority.findIndex(cdn => a.name.includes(cdn));
    const bIndex = priority.findIndex(cdn => b.name.includes(cdn));
    return aIndex - bIndex;
  });
}

2. Health Checking

Pre-check CDN availability before playback:

javascript
async function checkCDNHealth(url) {
  try {
    const response = await fetch(url, { method: 'HEAD' });
    return response.ok;
  } catch {
    return false;
  }
}

async function findHealthyCDN(hlsSources) {
  for (const source of hlsSources) {
    if (await checkCDNHealth(source.url)) {
      return source.url;
    }
  }
  return null;
}

3. Performance Monitoring

Track CDN performance for analytics:

javascript
function trackCDNPerformance(cdnUrl, loadTime, errors) {
  analytics.track('cdn_performance', {
    cdn: new URL(cdnUrl).hostname,
    loadTime,
    errors
  });
}

Troubleshooting

IssuePossible CauseSolution
All CDNs failingStream not activeCheck stream status via API
Slow switchingNo error handlingImplement proper error listeners
Region mismatchWrong CDN priorityUse region detection

Next Steps

Released under the MIT License.