Skip to content

HLS Playback Guide

Learn how to integrate HLS video playback into your web and mobile applications.

HLS Playback Flow

HLS URL Format

https://{cdn-host}/live/{streamKey}/hls.m3u8

Example:

https://stream.lunarstream.kozow.com/live/ee04affe2a669854052102fe762bd715/hls.m3u8

Available CDN Endpoints

Each stream is available through multiple CDN endpoints for redundancy:

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

Best Practice

Implement CDN failover in your player to automatically switch between endpoints if one becomes unavailable.

Adaptive Bitrate Streaming

Lunar Stream automatically provides multiple quality levels for adaptive bitrate streaming:

QualityResolutionBitrate
High1080p~6 Mbps
Medium720p~3 Mbps
Low480p~1.5 Mbps
Mobile360p~800 Kbps

The player automatically selects the best quality based on viewer's network conditions.

Web Player (Video.js)

Basic Setup

html
<!DOCTYPE html>
<html>
<head>
  <link href="https://vjs.zencdn.net/8.0.4/video-js.css" rel="stylesheet">
  <style>
    .video-container { max-width: 800px; margin: 0 auto; }
    .video-js { width: 100%; aspect-ratio: 16/9; }
  </style>
</head>
<body>
  <div class="video-container">
    <video id="live-player" class="video-js vjs-default-skin" controls>
      <source src="https://stream.lunarstream.kozow.com/live/YOUR_STREAM_KEY/hls.m3u8"
              type="application/x-mpegURL">
    </video>
  </div>

  <script src="https://vjs.zencdn.net/8.0.4/video.min.js"></script>
  <script>
    const player = videojs('live-player', {
      liveui: true,
      html5: {
        vhs: {
          overrideNative: true,
          enableLowInitialPlaylist: true
        }
      }
    });
  </script>
</body>
</html>

With CDN Failover

javascript
const player = videojs('live-player');

const cdnUrls = [
  'https://stream.lunarstream.kozow.com/live/STREAM_KEY/hls.m3u8',
  'https://zlmediakit-cdn.b-cdn.net/live/STREAM_KEY/hls.m3u8',
  'https://gcore-zlmediakit.lunarstream.kozow.com/live/STREAM_KEY/hls.m3u8'
];
let currentCdnIndex = 0;

player.on('error', function() {
  console.error('Player error:', player.error());
  tryNextCDN();
});

function tryNextCDN() {
  currentCdnIndex++;
  if (currentCdnIndex < cdnUrls.length) {
    player.src({ src: cdnUrls[currentCdnIndex], type: 'application/x-mpegURL' });
    player.play();
  } else {
    console.error('All CDNs failed');
  }
}

Web Player (HLS.js)

html
<video id="video" controls></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
  const video = document.getElementById('video');
  const hlsUrl = 'https://stream.lunarstream.kozow.com/live/STREAM_KEY/hls.m3u8';

  if (Hls.isSupported()) {
    const hls = new Hls();
    hls.loadSource(hlsUrl);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, () => video.play());
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    // Safari native HLS support
    video.src = hlsUrl;
    video.play();
  }
</script>

React Native (react-native-video)

javascript
import React, { useState, useRef } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import Video from 'react-native-video';

const LiveStreamPlayer = ({ hlsSources }) => {
  const videoRef = useRef(null);
  const [currentSourceIndex, setCurrentSourceIndex] = useState(0);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  const handleError = (err) => {
    console.error('Video error:', err);
    // Try next CDN source
    if (currentSourceIndex < hlsSources.length - 1) {
      setCurrentSourceIndex(prev => prev + 1);
      setError(null);
    } else {
      setError('Unable to load stream');
    }
  };

  if (error) {
    return <Text style={{ color: 'red' }}>{error}</Text>;
  }

  return (
    <View style={{ flex: 1 }}>
      {isLoading && <ActivityIndicator />}
      <Video
        ref={videoRef}
        source={{ uri: hlsSources[currentSourceIndex].url }}
        style={{ flex: 1 }}
        resizeMode="contain"
        onError={handleError}
        onLoad={() => setIsLoading(false)}
        onBuffer={({ isBuffering }) => setIsLoading(isBuffering)}
        controls
      />
    </View>
  );
};

export default LiveStreamPlayer;

iOS (AVPlayer)

swift
import AVKit

class StreamPlayerViewController: UIViewController {
    var player: AVPlayer?

    func playStream(hlsUrl: String) {
        guard let url = URL(string: hlsUrl) else { return }

        player = AVPlayer(url: url)
        let playerViewController = AVPlayerViewController()
        playerViewController.player = player

        present(playerViewController, animated: true) {
            self.player?.play()
        }
    }
}

Android (ExoPlayer)

kotlin
val player = ExoPlayer.Builder(context).build()
val mediaItem = MediaItem.fromUri(hlsUrl)
player.setMediaItem(mediaItem)
player.prepare()
player.play()

Troubleshooting

IssuePossible CauseSolution
Stream not loadingStream not startedCheck stream status via API
Playback bufferingNetwork issuesTry lower quality or different CDN
No video/audioCodec incompatibilityEnsure player supports HLS
CORS errorsCross-origin blockedUse CDN URLs provided by API

Next Steps

Released under the MIT License.