moosicbox_player 0.2.0

MoosicBox player package
docs.rs failed to build moosicbox_player-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: moosicbox_player-0.1.4

MoosicBox Player

A high-performance audio playback engine with support for multiple audio formats and session-based playback management.

Overview

The MoosicBox Player is the core audio playback component that provides:

  • Multi-Format Playback: Support for FLAC, AAC, MP3, and Opus
  • Session Management: Handle concurrent playback sessions with state tracking
  • Quality Control: Dynamic format conversion and sample rate resampling
  • Local & Remote Playback: Play files directly or stream from remote sources
  • HTTP API Integration: Control playback via REST endpoints

Features

Audio Format Support

The player supports the following audio formats (when corresponding feature flags are enabled):

  • FLAC - Lossless high-quality audio (decoder-flac, encoder-flac)
  • AAC/M4A - Efficient lossy compression (decoder-aac, encoder-aac)
  • MP3 - Universal compatibility (decoder-mp3, encoder-mp3)
  • Opus - Modern low-latency codec (decoder-opus, encoder-opus)

Playback Features

  • Gapless Playback - Seamless transitions between tracks
  • Seek Support - Precise position control within tracks
  • Volume Control - Per-session volume management
  • Pause/Resume - Full playback state control
  • Queue Management - Play albums, tracks, or playlists
  • Progress Tracking - Real-time playback position updates

Session Management

  • Multiple Sessions - Support concurrent playback sessions
  • Session State - Track playing status, position, volume, and quality
  • Playback Targets - Direct playback to specific audio zones
  • Event System - Broadcast playback state changes to listeners

Core Types

PlaybackHandler

The main interface for controlling playback:

use moosicbox_player::{PlaybackHandler, Player};

// Create a player implementation (e.g., LocalPlayer)
let mut handler = PlaybackHandler::new(player);

// Control playback
handler.play_track(session_id, profile, track, seek, volume, quality, playback_target, retry_options).await?;
handler.pause(retry_options).await?;
handler.resume(retry_options).await?;
handler.seek(position, retry_options).await?;
handler.next_track(seek, retry_options).await?;
handler.previous_track(seek, retry_options).await?;
handler.stop(retry_options).await?;

Player Trait

Implement this trait to create custom player backends:

#[async_trait]
pub trait Player: std::fmt::Debug + Send {
    // Optional hook: called before play event processing
    // Use this to execute custom logic before playback starts (e.g., state preparation, logging)
    async fn before_play_playback(&self, seek: Option<f64>) -> Result<(), PlayerError> {
        Ok(())
    }
    async fn trigger_play(&self, seek: Option<f64>) -> Result<(), PlayerError>;
    async fn trigger_stop(&self) -> Result<(), PlayerError>;
    async fn trigger_seek(&self, seek: f64) -> Result<(), PlayerError>;
    // Optional hook: called before playback state update
    // Use this to execute custom logic before state changes (e.g., validation, resource preparation)
    async fn before_update_playback(&self) -> Result<(), PlayerError> {
        Ok(())
    }
    // Optional hook: called after playback state update
    // Use this to execute custom logic after state changes (e.g., notifications, cleanup)
    async fn after_update_playback(&self) -> Result<(), PlayerError> {
        Ok(())
    }
    async fn trigger_pause(&self) -> Result<(), PlayerError>;
    async fn trigger_resume(&self) -> Result<(), PlayerError>;
    fn player_status(&self) -> Result<ApiPlaybackStatus, PlayerError>;
    fn get_source(&self) -> &PlayerSource;
}

Playback

The state object for active playback:

pub struct Playback {
    pub id: u64,
    pub session_id: u64,
    pub profile: String,
    pub tracks: Vec<Track>,
    pub playing: bool,
    pub position: u16,
    pub quality: PlaybackQuality,
    pub progress: f64,
    pub volume: Arc<AtomicF64>,
    pub playback_target: Option<PlaybackTarget>,
    pub abort: CancellationToken,
}

Usage

Local Player

The LocalPlayer (available with the local feature) plays audio directly using the audio output backend:

use moosicbox_player::{PlayerSource, PlaybackHandler};
use moosicbox_player::local::LocalPlayer;
use moosicbox_audio_output::default_output_factory;
use moosicbox_music_models::PlaybackQuality;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a local player
    let local_player = LocalPlayer::new(
        PlayerSource::Local,
        None, // playback type (defaults to Default)
    ).await?;

    // Attach an audio output
    let local_player = local_player.with_output(
        default_output_factory().await
            .ok_or("Missing default audio output")?
    );

    // Create a playback handler
    let playback = local_player.playback.clone();
    let output = local_player.output.clone();
    let mut handler = PlaybackHandler::new(local_player)
        .with_playback(playback)
        .with_output(output);

    // Play a track
    handler.play_track(
        session_id,
        profile,
        track,
        None, // seek
        Some(0.8), // volume
        PlaybackQuality::default(),
        None, // playback_target
        None, // retry_options
    ).await?;

    Ok(())
}

Playing Tracks

use moosicbox_player::PlaybackHandler;
use moosicbox_music_models::{Track, AudioFormat, PlaybackQuality};

async fn play_example(
    handler: &mut PlaybackHandler,
    track: Track,
    session_id: u64,
    profile: String,
) -> Result<(), Box<dyn std::error::Error>> {
    // Play a single track
    handler.play_track(
        session_id,
        profile.clone(),
        track,
        None,
        Some(1.0),
        PlaybackQuality { format: AudioFormat::Source },
        None,
        None,
    ).await?;

    Ok(())
}

Playing Albums

use moosicbox_music_api::MusicApi;
use moosicbox_music_models::id::Id;

async fn play_album_example(
    handler: &mut PlaybackHandler,
    api: &dyn MusicApi,
    album_id: &Id,
    session_id: u64,
    profile: String,
) -> Result<(), Box<dyn std::error::Error>> {
    // Play an entire album
    handler.play_album(
        api,
        session_id,
        profile,
        album_id,
        None, // position
        None, // seek
        Some(1.0), // volume
        PlaybackQuality::default(),
        None, // playback_target
        None, // retry_options
    ).await?;

    Ok(())
}

Controlling Playback

use moosicbox_player::DEFAULT_PLAYBACK_RETRY_OPTIONS;

async fn control_playback(
    handler: &mut PlaybackHandler,
) -> Result<(), Box<dyn std::error::Error>> {
    // Pause playback
    handler.pause(Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    // Resume playback
    handler.resume(Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    // Seek to 30 seconds
    handler.seek(30.0, Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    // Skip to next track
    handler.next_track(None, Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    // Go to previous track
    handler.previous_track(None, Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    // Stop playback
    handler.stop(Some(DEFAULT_PLAYBACK_RETRY_OPTIONS)).await?;

    Ok(())
}

Updating Playback State

async fn update_playback(
    handler: &mut PlaybackHandler,
    session_id: u64,
    profile: String,
) -> Result<(), Box<dyn std::error::Error>> {
    handler.update_playback(
        true,              // modify_playback
        None,              // play
        None,              // stop
        Some(true),        // playing
        Some(2),           // position (track index)
        Some(15.0),        // seek
        Some(0.7),         // volume
        None,              // tracks
        None,              // quality
        Some(session_id),
        Some(profile),
        None,              // playback_target
        true,              // trigger_event
        None,              // retry_options
    ).await?;

    Ok(())
}

Event Handling

Listen for playback state changes:

use moosicbox_player::{on_playback_event, Playback};
use moosicbox_session::models::UpdateSession;

fn my_event_handler(update: &UpdateSession, playback: &Playback) {
    if let Some(playing) = update.playing {
        println!("Playback state changed: {}", playing);
    }
    if let Some(position) = update.position {
        println!("Track position changed: {}", position);
    }
    if let Some(seek) = update.seek {
        println!("Seek position: {:.2}s", seek);
    }
    if let Some(volume) = update.volume {
        println!("Volume changed: {:.2}", volume);
    }
}

// Register event listener
on_playback_event(my_event_handler);

HTTP API Integration

When used with the MoosicBox Server, the player provides REST endpoints for playback control. All endpoints require a profile via either moosicbox-profile header or moosicboxProfile query parameter.

Play Track

POST /player/play/track?moosicboxProfile=default&sessionId=1&trackId=123&volume=0.8

Play Album

POST /player/play/album?moosicboxProfile=default&sessionId=1&albumId=456&position=0

Play Multiple Tracks

POST /player/play/tracks?moosicboxProfile=default&sessionId=1&trackIds=123,124,125&position=0

Pause/Resume

POST /player/pause?moosicboxProfile=default
POST /player/resume?moosicboxProfile=default

Seek

POST /player/seek?moosicboxProfile=default&seek=45.5

Next/Previous Track

POST /player/next-track?moosicboxProfile=default
POST /player/previous-track?moosicboxProfile=default

Stop

POST /player/stop?moosicboxProfile=default

Get Status

GET /player/status?moosicboxProfile=default

Update Playback

POST /player/update-playback?moosicboxProfile=default&playing=true&position=2&volume=0.7

Configuration

Feature Flags

The player supports various feature flags for customization:

Audio Output Backends:

  • cpal - Cross-platform audio output (default)
  • jack - JACK audio server support
  • asio - ASIO low-latency support (Windows)

Audio Decoders:

  • decoder-aac - AAC audio decoding
  • decoder-flac - FLAC audio decoding
  • decoder-mp3 - MP3 audio decoding
  • decoder-opus - Opus audio decoding
  • all-decoders - Enable all decoders

Audio Encoders:

  • encoder-aac - AAC audio encoding
  • encoder-flac - FLAC audio encoding
  • encoder-mp3 - MP3 audio encoding
  • encoder-opus - Opus audio encoding
  • all-encoders - Enable all encoders

Other Features:

  • api - Enable HTTP API endpoints
  • openapi - Generate OpenAPI documentation
  • local - Enable local player implementation
  • profiling - Enable performance profiling

PlayerSource

Configure where audio is sourced from:

use moosicbox_player::PlayerSource;

// Play local files
let source = PlayerSource::Local;

// Stream from remote server
let source = PlayerSource::Remote {
    host: "http://localhost:8001".to_string(),
    query: None,
    headers: None,
};

PlaybackQuality

Specify output audio format:

use moosicbox_music_models::{PlaybackQuality, AudioFormat};

let quality = PlaybackQuality {
    format: AudioFormat::Source,  // Use source format
};

let quality = PlaybackQuality {
    format: AudioFormat::Flac,    // Convert to FLAC
};

PlaybackRetryOptions

Configure retry behavior for operations:

use moosicbox_player::PlaybackRetryOptions;
use std::time::Duration;

let retry_options = PlaybackRetryOptions {
    max_attempts: 10,
    retry_delay: Duration::from_millis(500),
};

Error Handling

use moosicbox_player::PlayerError;

match handler.play_track(/* ... */).await {
    Ok(()) => println!("Playback started"),
    Err(PlayerError::TrackNotFound(id)) => {
        eprintln!("Track {} not found", id);
    },
    Err(PlayerError::UnsupportedFormat(format)) => {
        eprintln!("Unsupported audio format: {:?}", format);
    },
    Err(PlayerError::NoPlayersPlaying) => {
        eprintln!("No active playback session");
    },
    Err(PlayerError::PositionOutOfBounds(pos)) => {
        eprintln!("Position {} is out of bounds", pos);
    },
    Err(e) => {
        eprintln!("Playback error: {:?}", e);
    }
}

Architecture

The player is built on several key components:

  • PlaybackHandler - High-level playback control interface
  • Player trait - Pluggable player backend system
  • LocalPlayer - Direct audio output implementation
  • Symphonia integration - Audio decoding via symphonia
  • Signal chain - Audio processing pipeline for format conversion
  • Audio output - Hardware audio output via moosicbox_audio_output

Dependencies

Key dependencies from Cargo.toml:

  • moosicbox_audio_decoder - Audio format decoding
  • moosicbox_audio_output - Audio output backends
  • moosicbox_music_api - Music metadata and track fetching
  • moosicbox_music_models - Track and album data models
  • moosicbox_session - Session and playlist management
  • moosicbox_resampler - Sample rate conversion
  • symphonia - Audio codec support
  • actix-web - HTTP API endpoints (with api feature)

See Also