11 个版本 (7 个重大变更)

0.8.0 2024年2月6日
0.7.2 2023年8月24日
0.6.0 2023年2月12日
0.5.0 2022年3月22日
0.1.0 2019年8月13日

#19 in 多媒体

Download history 1678/week @ 2024-04-29 1630/week @ 2024-05-06 1273/week @ 2024-05-13 1437/week @ 2024-05-20 1111/week @ 2024-05-27 1381/week @ 2024-06-03 1244/week @ 2024-06-10 1082/week @ 2024-06-17 1049/week @ 2024-06-24 1509/week @ 2024-07-01 2309/week @ 2024-07-08 2059/week @ 2024-07-15 2003/week @ 2024-07-22 1930/week @ 2024-07-29 2269/week @ 2024-08-05 2797/week @ 2024-08-12

9,168 每月下载量
用于 9 个包8 个直接使用)

MIT 许可证

490KB
11K SLoC

pipewire

PipeWire 的 Rust 绑定。

这些绑定提供了一个安全的 API,可以用来与 PipeWire 交互。

文档

请参阅 crate 文档


lib.rs:

Rust 对 pipewire 的绑定

pipewire 是一个 crate,提供了对 libpipewire(与 pipewire 服务器交互的库)的 rustic 绑定。

与 pipewire 交互的程序通常通过注册回调来响应来自服务器的事件,并通过在本地代理对象上调用方法来调用服务器上对象的方法。

入门

大多数与 pipewire 交互的程序都需要一些基本对象

  • 一个 MainLoop,它驱动程序,响应任何传入的事件并将方法调用分派。大多数时候,程序/线程将空闲在这个循环中,等待事件发生。
  • 一个 Context,用于跟踪任何 pipewire 资源。
  • 一个 Core,它是远程 pipewire 实例的代理,用于向远程服务器发送消息并接收事件。
  • 可选的,一个 Registry,可以用来管理和跟踪服务器上可用的对象。

它们可以这样创建

use pipewire::{main_loop::MainLoop, context::Context};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mainloop = MainLoop::new(None)?;
    let context = Context::new(&mainloop)?;
    let core = context.connect(None)?;
    let registry = core.get_registry()?;

    Ok(())
}

现在你可以开始将不同类型的回调连接到对象,以响应事件,并通过调用对象上的方法来更改远程的状态。

use pipewire::{main_loop::MainLoop, context::Context};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mainloop = MainLoop::new(None)?;
    let context = Context::new(&mainloop)?;
    let core = context.connect(None)?;
    let registry = core.get_registry()?;

    // Register a callback to the `global` event on the registry, which notifies of any new global objects
    // appearing on the remote.
    // The callback will only get called as long as we keep the returned listener alive.
    let _listener = registry
        .add_listener_local()
        .global(|global| println!("New global: {:?}", global))
        .register();

    // Calling the `destroy_global` method on the registry will destroy the object with the specified id on the remote.
    // We don't have a specific object to destroy now, so this is commented out.
    # // FIXME: Find a better method for this example we can actually call.
    // registry.destroy_global(313).into_result()?;

    mainloop.run();

    Ok(())
}

请注意,注册任何回调都需要闭包具有 'static 生命周期,因此如果您需要捕获任何变量,请使用 move || 闭包,并使用 std::rc::Rc 来访问共享变量,如果您需要修改它们,则使用一些 std::cell 变体。

还请注意,我们在最后调用了 mainloop.run()。这将进入循环,并且只有在从某些事件中调用 mainloop.quit() 时才会返回。如果我们没有运行循环,事件和方法调用将不会被处理,因此程序将无法完成任何操作而终止。

主循环

有时,即使我们在主循环中等待,也需要做其他事情。
这可以通过向循环中添加源来实现。

例如,我们可以在间隔上调用一个函数

use pipewire::main_loop::MainLoop;
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mainloop = MainLoop::new(None)?;

    let timer = mainloop.loop_().add_timer(|_| println!("Hello"));
    // Call the first time in half a second, and then in a one second interval.
    timer.update_timer(Some(Duration::from_millis(500)), Some(Duration::from_secs(1))).into_result()?;

    mainloop.run();

    Ok(())
}

此程序将每秒打印出 "Hello",永远如此。

使用类似的方法,您也可以对IO或信号做出反应,或者当循环空闲时调用回调。

多线程

pipewire库实际上并不是线程安全的,因此pipewire对象没有实现 SendSync

然而,您可以在另一个线程中启动一个 MainLoop 并使用两个通道进行双向通信。

要向主线程发送消息,我们可以轻松使用一个 std::sync::mpsc。因为我们卡在pipewire线程中的主循环中,不能简单地阻塞在接收消息,所以我们使用一个 pipewire::channel

有关详细信息,请参阅 pipewire::channel 模块。

依赖项

~3.5–7MB
~127K SLoC