#hls #rodio #media

hls_client

Library to generate a single stream from HLS segments

2 stable releases

new 1.0.1 Mar 28, 2025

#130 in Video

Download history 166/week @ 2025-03-23

166 downloads per month

Custom license

34KB
639 lines

HLS client

This library provides a client for HLS (HTTP Live Streaming) protocol. It is still a work in progress and does not completely implement RFC 8216.

Use cases

Normally, HLS playback can be achieved by individually loading each segment as a different media source in a player. However in most cases, this adds a minor delay between 2 segments introduced by the media player application preparing a new decoder for the next segment.

This library combines all segments into a single stream. This approach only works when all the segments are of the same type (e.g., same container and codec).

Goals

This library aims to provide a simple interface for usage with rodio player or other media players which accept a single stream.

It does not and will not provide preloading or caching of segments. This can be achieved by using a wrapper around streams such as stream-download-rs. We do provide an interface which can be used to use this library with stream-download-rs without any additional setup.

Usage with rodio

Without stream-download-rs

This can be achieved by using HLSDecoder directly.

use std::error::Error;

use hls_client::{config::ConfigBuilder, decoder::HLSDecoder};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    let decoder = HLSDecoder::new(
        ConfigBuilder::new()
            .url("https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8")?
            .build()?,
    )
    .await?;

    let handle = tokio::task::spawn_blocking(move || {
        let (_stream, handle) = rodio::OutputStream::try_default()?;
        let sink = rodio::Sink::try_new(&handle)?;
        sink.append(rodio::Decoder::new(decoder)?);
        sink.sleep_until_end();

        Ok::<_, Box<dyn Error + Send + Sync>>(())
    });
    handle.await??;

    Ok(())
}

With stream-download-rs

This can be achieved using HLSStream directly.

use std::{error::Error, num::NonZeroUsize, path::PathBuf, str::FromStr};

use hls_client::{config::ConfigBuilder, stream::HLSStream};
use stream_download::{
    storage::{adaptive::AdaptiveStorageProvider, temp::TempStorageProvider},
    Settings, StreamDownload,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    let settings = Settings::default();
    let decoder = StreamDownload::new::<HLSStream>(
        ConfigBuilder::new()
            .url("https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8")?
            .build()?,
        AdaptiveStorageProvider::new(
            TempStorageProvider::new(),
            NonZeroUsize::new((settings.get_prefetch_bytes() * 2) as usize).unwrap(),
        ),
        settings,
    )
    .await?;

    let handle = tokio::task::spawn_blocking(move || {
        let (_stream, handle) = rodio::OutputStream::try_default()?;
        let sink = rodio::Sink::try_new(&handle)?;
        sink.append(rodio::Decoder::new(decoder)?);
        sink.sleep_until_end();

        Ok::<_, Box<dyn Error + Send + Sync>>(())
    });
    handle.await??;

    Ok(())
}

Dependencies

~6–18MB
~230K SLoC