//! Mixer API - Simple Mixer API for mixer control //! use std::ffi::{CStr, CString}; use std::{ptr, mem, fmt, ops}; use libc::{c_long, c_int, c_uint, c_short, pollfd}; usecrate::poll;
impl Mixer { /// Opens a mixer and attaches it to a card identified by its name (like hw:0) and loads the /// mixer after registering a Selem. pubfn new(name: &str, nonblock: bool) -> Result<Mixer> { letmut mixer = Mixer::open(nonblock)?;
mixer.attach(&CString::new(name).unwrap())?;
Selem::register(&mut mixer)?;
mixer.load()?;
Ok(mixer)
}
/// Creates a Selem by looking for a specific selem by name given a mixer (of a card) pubfn find_selem(&self, id: &SelemId) -> Option<Selem> { let selem = unsafe { alsa::snd_mixer_find_selem(self.0, id.as_ptr()) };
pubfn iter(&self) -> Iter {
Iter {
last_handle: ptr::null_mut(),
mixer: self
}
}
pubfn handle_events(&self) -> Result<u32> {
acheck!(snd_mixer_handle_events(self.0)).map(|x| x as u32)
}
pubfn wait(&self, timeout_ms: Option<u32>) -> Result<()> {
acheck!(snd_mixer_wait(self.0, timeout_ms.map(|x| x as c_int).unwrap_or(-1))).map(|_| ()) }
}
/// Closes mixer and frees used resources impl Drop for Mixer { fn drop(&mutself) { unsafe { alsa::snd_mixer_close(self.0) };
}
}
impl poll::Descriptors for Mixer { fn count(&self) -> usize { unsafe { alsa::snd_mixer_poll_descriptors_count(self.0) as usize }
} fn fill(&self, p: &mut [pollfd]) -> Result<usize> { let z = unsafe { alsa::snd_mixer_poll_descriptors(self.0, p.as_mut_ptr(), p.len() as c_uint) };
from_code("snd_mixer_poll_descriptors", z).map(|_| z as usize)
} fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> { letmut r = 0; let z = unsafe { alsa::snd_mixer_poll_descriptors_revents(self.0, p.as_ptr() as *mut pollfd, p.len() as c_uint, &mut r) };
from_code("snd_mixer_poll_descriptors_revents", z).map(|_| poll::Flags::from_bits_truncate(r as c_short))
}
}
/// Wrapper for a mB (millibel) value. /// /// Despite some ALSA functions named "dB", they actually take mB values instead. /// This is a wrapper type to help with those calculations. Its interior is the /// actual mB value. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pubstruct MilliBel(pub i64);
pubfn new(name: &str, index: u32) -> SelemId { letmut s = SelemId::empty();
s.set_name(&CString::new(name).unwrap());
s.set_index(index);
s
}
/// Returns an empty (zeroed) SelemId. This id is not a usable id and need to be initialized /// like `SelemId::new()` does pubfn empty() -> SelemId {
assert!(unsafe { alsa::snd_mixer_selem_id_sizeof() } as usize <= SELEM_ID_SIZE); // Create empty selem_id and fill from mixer
SelemId(unsafe { mem::zeroed() })
}
/// Convert SelemId into ``*mut snd_mixer_selem_id_t` that the alsa call needs. /// See [snd_mixer_selem_id_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___simple_mixer.html) #[inline] fn as_ptr(&self) -> *mut alsa::snd_mixer_selem_id_t { self.0.as_ptr() as *const _ as *mut alsa::snd_mixer_selem_id_t
}
pubfn get_name(&self) -> Result<&str> { let c = unsafe { alsa::snd_mixer_selem_id_get_name(self.as_ptr()) };
from_const("snd_mixer_selem_id_get_name", c)
}
/// TODO: This function might change to support regopt and to return the mixer class pubfn register(mixer: &mut Mixer) -> Result<()> {
acheck!(snd_mixer_selem_register(mixer.0, ptr::null_mut(), ptr::null_mut())).map(|_| ())
}
pubfn get_id(&self) -> SelemId { let id = SelemId::empty(); unsafe { alsa::snd_mixer_selem_get_id(self.handle, id.as_ptr()) };
id
}
/// Gets name from snd_mixer_selem_channel_name pubfn channel_name(channel: SelemChannelId) -> Result<&'static str> { let c = unsafe { alsa::snd_mixer_selem_channel_name(channel as i32) };
from_const("snd_mixer_selem_channel_name", c)
}
/// Asks alsa to convert capture volume to millibels pubfn ask_capture_vol_db(&self, volume: i64) -> Result<MilliBel> { letmut decibel_value: c_long = 0;
acheck!(snd_mixer_selem_ask_capture_vol_dB (self.handle, volume as c_long, &='color:red'>mut decibel_value))
.map(|_| MilliBel(decibel_value as i64))
}
// Asks alsa to convert millibels to capture volume. pubfn ask_capture_db_vol(&self, db: MilliBel, dir: Round) -> Result<i64> { letmut raw_volume: c_long = 0;
acheck!(snd_mixer_selem_ask_capture_dB_vol(self.handle, db.0as c_long, dir as c_int, &pan style='color:red'>mut raw_volume))
.map(|_| raw_volume as i64)
}
pubfn set_playback_volume(&self, channel: SelemChannelId, value: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_playback_volume(self.handle, channel as i32, value as c_long)).map(|_| ())
}
pubfn set_playback_volume_range(&self, min: i64, max: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_playback_volume_range(self.handle, min as c_long, max as c_long)).map(|_| ())
}
pubfn set_playback_volume_all(&self, value: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_playback_volume_all(self.handle, value as c_long)).map(|_| ())
}
pubfn set_playback_db(&self, channel: SelemChannelId, value: MilliBel, dir: Round) -> Result<()> {
acheck!(snd_mixer_selem_set_playback_dB(self.handle, channel as i32, *value as c_long, dir as c_int)).map(|_| ())
}
pubfn set_capture_db(&self, channel: SelemChannelId, value: MilliBel, dir: Round) -> Result<()> {
acheck!(snd_mixer_selem_set_capture_dB(self.handle, channel as i32, *value as c_long, dir as c_int)).map(|_| ())
}
pubfn set_playback_db_all(&self, value: MilliBel, dir: Round) -> Result<()> {
acheck!(snd_mixer_selem_set_playback_dB_all(self.handle, *value as c_long, dir as c_int)).map(|_| ())
}
pubfn set_capture_db_all(&self, value: MilliBel, dir: Round) -> Result<()> {
acheck!(snd_mixer_selem_set_capture_dB_all(self.handle, *value as c_long, dir as c_int)).map(|_| ())
}
pubfn set_capture_volume(&self, channel: SelemChannelId, value: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_capture_volume(self.handle, channel as i32, value as c_long)).map(|_| ())
}
pubfn set_capture_volume_range(&self, min: i64, max: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_capture_volume_range(self.handle, min as c_long, max as c_long)).map(|_| ())
}
pubfn set_capture_volume_all(&self, value: i64) -> Result<()> {
acheck!(snd_mixer_selem_set_capture_volume_all(self.handle, value as c_long)).map(|_| ())
}
for card in card::Iter::new().map(|c| c.unwrap()) {
println!("Card #{}: {} ({})", card.get_index(), card.get_name().unwrap(), card.get_longname().unwrap());
let mixer = Mixer::new(&format!("hw:{}", card.get_index()), false).unwrap(); for selem in mixer.iter().filter_map(|e| Selem::new(e)) {
let sid = selem.get_id();
println!("\tMixer element {},{}:", sid.get_name().unwrap(), sid.get_index());
if selem.has_volume() {
print!("\t Volume limits: "); if selem.has_capture_volume() { let (vmin, vmax) = selem.get_capture_volume_range(); let (mbmin, mbmax) = selem.get_capture_db_range();
print!("Capture = {} - {}", vmin, vmax);
print!(" ({} dB - {} dB)", mbmin.to_db(), mbmax.to_db());
} if selem.has_playback_volume() { let (vmin, vmax) = selem.get_playback_volume_range(); let (mbmin, mbmax) = selem.get_playback_db_range();
print!("Playback = {} - {}", vmin, vmax);
print!(" ({} dB - {} dB)", mbmin.to_db(), mbmax.to_db());
}
println!();
}
if selem.is_enumerated() {
print!("\t Valid values: "); for v in selem.iter_enum().unwrap() { print!("{}, ", v.unwrap()) };
print!("\n\t Current values: "); for v in SelemChannelId::all().iter().filter_map(|&v| selem.get_enum_item(v).ok()) {
print!("{}, ", selem.get_enum_item_name(v).unwrap());
}
println!();
}
if selem.can_capture() {
print!("\t Capture channels: "); if selem.is_capture_mono() {
print!("Mono");
} else { for channel in SelemChannelId::all() { if selem.has_capture_channel(*channel) { print!("{}, ", channel) };
}
}
println!();
print!("\t Capture volumes: "); for channel in SelemChannelId::all() { if selem.has_capture_channel(*channel) { print!("{}: {} ({} dB), ", channel, match selem.get_capture_volume(*channel) {Ok(v) => format!("{}", v), Err(_) => "n/a".to_string()}, match selem.get_capture_vol_db(*channel) {Ok(v) => format!("{}", v.to_db()), Err(_) => "n/a".to_string()}
);}
}
println!();
}
if selem.can_playback() {
print!("\t Playback channels: "); if selem.is_playback_mono() {
print!("Mono");
} else { for channel in SelemChannelId::all() { if selem.has_playback_channel(*channel) { print!("{}, ", channel) };
}
}
println!(); if selem.has_playback_volume() {
print!("\t Playback volumes: "); for channel in SelemChannelId::all() { if selem.has_playback_channel(*channel) { print!("{}: {} / {}dB, ",
channel, match selem.get_playback_volume(*channel) {Ok(v) => format!("{}", v), Err(_) => "n/a".to_string()}, match selem.get_playback_vol_db(*channel) {Ok(v) => format!("{}", v.to_db()), Err(_) => "n/a".to_string()}
);}
}
println!();
}
}
}
}
}
#[test] #[ignore] fn get_and_set_playback_volume() { let mixer = Mixer::new("hw:1", false).unwrap(); let selem = mixer.find_selem(&SelemId::new("Master", 0)).unwrap();
let (rmin, rmax) = selem.get_playback_volume_range(); letmut channel = SelemChannelId::mono(); for c in SelemChannelId::all().iter() { if selem.has_playback_channel(*c) { channel = *c; break }
}
println!("Testing on {} with limits {}-{} on channel {}", selem.get_id().get_name().unwrap(), rmin, rmax, channel);
let old: i64 = selem.get_playback_volume(channel).unwrap(); let new: i64 = rmax / 2;
assert_ne!(new, old);
println!("Changing volume of {} from {} to {}", channel, old, new);
selem.set_playback_volume(channel, new).unwrap(); letmut result: i64 = selem.get_playback_volume(channel).unwrap();
assert_eq!(new, result);
// return volume to old value
selem.set_playback_volume(channel, old).unwrap();
result = selem.get_playback_volume(channel).unwrap();
assert_eq!(old, result);
}
#[test] #[ignore] fn get_and_set_capture_volume() { let mixer = Mixer::new("hw:1", false).unwrap(); let selem = mixer.find_selem(&SelemId::new("Capture", 0)).unwrap();
let (rmin, rmax) = selem.get_capture_volume_range(); letmut channel = SelemChannelId::mono(); for c in SelemChannelId::all().iter() { if selem.has_playback_channel(*c) { channel = *c; break }
}
println!("Testing on {} with limits {}-{} on channel {}", selem.get_id().get_name().unwrap(), rmin, rmax, channel);
let old: i64 = selem.get_capture_volume(channel).unwrap(); let new: i64 = rmax / 2;
assert_ne!(new, old);
println!("Changing volume of {} from {} to {}", channel, old, new);
selem.set_capture_volume(channel, new).unwrap(); letmut result: i64 = selem.get_capture_volume(channel).unwrap();
assert_eq!(new, result);
// return volume to old value
selem.set_capture_volume(channel, old).unwrap();
result = selem.get_capture_volume(channel).unwrap();
assert_eq!(old, result);
}
#[test] fn print_sizeof() { let selemid = unsafe { alsa::snd_mixer_selem_id_sizeof() } as usize;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.27Bemerkung:
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.