如何用Rust与pipewire-rs获取默认音视频输入输出设备?
获取PipeWire默认音视频设备的解决方案
PipeWire的默认设备信息并不直接暴露在Device对象中,而是需要通过Node对象(PipeWire中用于音频/视频流的端点实体)来识别。以下是两种可行的实现方案:
方案1:监听Node对象识别默认设备
PipeWire的默认音频输入、输出和视频输出对应特定的Node,这些Node会带有node.is-default=true的属性标识。你需要在Registry监听中添加对ObjectType::Node的处理,通过属性筛选出默认设备:
修改后的完整代码:
use std::thread; use std::thread::JoinHandle; use gtk::glib::ExitCode; use pipewire::{Context, Core, MainLoop}; use pipewire::spa::ReadableDict; use pipewire::types::ObjectType; pub fn mypipewrite_spawn_mainloop() -> JoinHandle<ExitCode> { let pw_thread = thread::spawn(|| { let mainloop = MainLoop::new().expect("failed to get main loop"); let context = Context::new(&mainloop).expect("failed to get context"); let core = context.connect(None).expect("failed to get core"); let registry = core.get_registry().expect("failed to get registry"); let _listener = registry .add_listener_local() .global(|global| { if global.type_ == ObjectType::Port { // 原Port处理逻辑不变 let props = global.props.as_ref().unwrap(); let port_name = props.get("port.name"); let port_alias = props.get("port.alias"); let object_path = props.get("object.path"); let format_dsp = props.get("format.dsp"); let audio_channel = props.get("audio.channel"); let port_id = props.get("port.id"); let port_direction = props.get("port.direction"); println!("Port: Name: {:?} Alias: {:?} Id: {:?} Direction: {:?} AudioChannel: {:?} Object Path: {:?} FormatDsp: {:?}", port_name, port_alias, port_id, port_direction, audio_channel, object_path, format_dsp ); } else if global.type_ == ObjectType::Device { // 原Device处理逻辑不变 let props = global.props.as_ref().unwrap(); let device_name = props.get("device.name"); let device_nick = props.get("device.nick"); let device_description = props.get("device.description"); let device_api = props.get("device.api"); let media_class = props.get("media.class"); println!("Device: Name: {:?} Nick: {:?} Desc: {:?} Api: {:?} MediaClass: {:?}", device_name, device_nick, device_description, device_api, media_class ); } else if global.type_ == ObjectType::Node { let props = global.props.as_ref().unwrap(); let node_name = props.get("node.name"); let node_description = props.get("node.description"); let media_class = props.get("media.class"); let device_id = props.get("device.id"); let is_default = props.get("node.is-default"); // 识别默认音频输出 if media_class == Some("Audio/Sink") && is_default == Some("true") { println!("默认音频输出Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}", node_name, node_description, device_id ); } // 识别默认音频输入 if media_class == Some("Audio/Source") && is_default == Some("true") { println!("默认音频输入Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}", node_name, node_description, device_id ); } // 识别默认视频输出(摄像头) if media_class == Some("Video/Source") && is_default == Some("true") { println!("默认视频输出Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}", node_name, node_description, device_id ); } } }) .register(); mainloop.run(); ExitCode::FAILURE }); pw_thread }
方案2:直接调用Core的默认节点查询API
pipewire-rs的Core结构体提供了get_default_node方法,可以直接查询指定类型的默认节点,这种方式更简洁(需要异步处理):
// 在core创建后添加以下异步查询逻辑 use pipewire::core::NodeType; use tokio::runtime::Runtime; // 初始化Tokio运行时处理异步调用 let runtime = Runtime::new().unwrap(); runtime.block_on(async { // 查询默认音频输出 if let Ok(default_sink) = core.get_default_node(NodeType::AudioSink).await { let props = default_sink.props().unwrap(); println!("默认音频输出: {:?}", props.get("node.description")); } // 查询默认音频输入 if let Ok(default_source) = core.get_default_node(NodeType::AudioSource).await { let props = default_source.props().unwrap(); println!("默认音频输入: {:?}", props.get("node.description")); } // 查询默认视频输出 if let Ok(default_video_source) = core.get_default_node(NodeType::VideoSource).await { let props = default_video_source.props().unwrap(); println!("默认视频输出: {:?}", props.get("node.description")); } });
关键说明
- PipeWire中
Device是硬件设备抽象,Node是实际可用于流传输的端点,默认设备对应带有node.is-default=true属性的Node - 如果
node.is-default属性不存在,可通过node.priority值判断,优先级最高的即为默认设备 - 视频输出设备通常对应
Video/Source类型的Node,对应摄像头等视频采集设备
内容的提问来源于stack exchange,提问作者ufk
相关产品推荐
相关产品推荐

