smtc-suite

Crates.iosmtc-suite
lib.rssmtc-suite
version2.6.1
created_at2025-06-19 19:00:05.79911+00
updated_at2025-12-06 18:04:24.775851+00
description一个用于与 Windows 系统媒体控件 (SMTC) 和系统音频进行交互的 Rust 库。
homepage
repositoryhttps://github.com/apoint123/smtc-suite
max_upload_size
id1718691
size275,564
(apoint123)

documentation

https://docs.rs/crate/smtc-suite

README

smtc-suite

Crates.io Docs.rs

A Rust library for interacting with Windows System Media Transport Controls (SMTC) and system audio.

smtc-suite provides a safe and efficient API for listening to and controlling media playback on Windows, capturing system audio output, and managing individual application volumes.

Core Features

  • Media Session Monitoring: Automatically discovers all SMTC-enabled media sources in the system (like Spotify, Groove Music, etc.) and retrieves currently playing track information (title, artist, album, thumbnail).
  • Media Playback Control: Sends playback commands such as play, pause, skip, and seek to the currently active media session.
  • System Audio Capture: Captures the system's currently playing audio stream in loopback mode and provides functionality to resample it to a unified format.
  • Independent Volume Control: Finds the audio session for a specific application and independently gets or sets its volume.
  • Asynchronous & Event-Driven: All background operations are handled in a separate, efficient asynchronous worker thread, communicating with the main application via channels without blocking your app's main thread.

Usage

The sole entry point for interacting with this library is the MediaManager::start() function.

  1. Calling MediaManager::start() launches all necessary background services and returns a tuple: (MediaController, mpsc::Receiver<MediaUpdate>).
  2. The MediaController struct is your handle for sending commands to the background service. It contains a command_tx field for sending MediaCommands.
  3. The mpsc::Receiver<MediaUpdate> is the channel through which you receive all status updates and events from the background.
  4. You can loop on this Receiver in a separate task to receive real-time updates.
  5. When your application exits, be sure to call MediaController::shutdown() or send a MediaCommand::Shutdown to gracefully shut down the background thread.

Example

use smtc_suite::{MediaManager, MediaCommand, MediaUpdate};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Start the media service and get the controller and update receiver.
    let (controller, mut update_rx) = MediaManager::start()?;

    // It is recommended to handle update events from the background in a separate Tokio task.
    let update_task = tokio::spawn(async move {
        // Loop to receive updates until the channel is closed.
        while let Some(update) = update_rx.recv().await {
            match update {
                MediaUpdate::TrackChanged(info) => {
                    println!(
                        "Track Changed: {} - {}",
                        info.artist.unwrap_or_default(),
                        info.title.unwrap_or_default()
                    );
                }
                MediaUpdate::SessionsChanged(sessions) => {
                    println!("Available media session list updated, total: {}.", sessions.len());
                }
                MediaUpdate::AudioData(data) => {
                    println!("Received {} bytes of audio data.", data.len());
                }
                _ => { /* Handle other updates */ }
            }
        }
        println!("Update channel closed, event listener task exiting.");
    });

    // In the main task, we can send commands.
    // For example, wait for 5 seconds then start audio capture.
    println!("Starting audio capture in 5 seconds...");
    tokio::time::sleep(Duration::from_secs(5)).await;
    controller.command_tx.send(MediaCommand::StartAudioCapture).await?;

    // Wait for another 10 seconds.
    println!("Audio capture started, shutting down the service in 10 seconds...");
    tokio::time::sleep(Duration::from_secs(10)).await;

    // 3. Before the program exits, send the shutdown command.
    println!("Sending shutdown command...");
    controller.shutdown().await?;

    // Wait for the update task to finish.
    update_task.await?;

    println!("Program has exited gracefully.");

    Ok(())
}

LICENSE

MIT

Commit count: 60

cargo fmt