1use core::ffi::CStr;
4use ::alloc::ffi::CString;
5use ::alloc::string::String;
6use core::{ptr, mem, fmt, ops};
7use libc::{c_long, c_int, c_uint, c_short, pollfd};
8use crate::poll;
9
10use crate::alsa;
11use super::Round;
12use super::error::*;
13
14const SELEM_ID_SIZE: usize = 64;
15
16#[derive(Debug)]
18pub struct Mixer(*mut alsa::snd_mixer_t);
19
20unsafe impl Send for Mixer {}
21
22impl Mixer {
23 pub fn new(name: &str, nonblock: bool) -> Result<Mixer> {
26 let mut mixer = Mixer::open(nonblock)?;
27 mixer.attach(&CString::new(name).unwrap())?;
28 Selem::register(&mut mixer)?;
29 mixer.load()?;
30 Ok(mixer)
31 }
32
33 pub fn find_selem(&self, id: &SelemId) -> Option<Selem<'_>> {
35 let selem = unsafe { alsa::snd_mixer_find_selem(self.0, id.as_ptr()) };
36
37 if selem.is_null() { None }
38 else { Some(Selem(Elem {handle: selem, _mixer: self})) }
39 }
40
41 pub fn open(nonblock: bool) -> Result<Mixer> {
42 let mut r = ptr::null_mut();
43 let flags = if nonblock { 1 } else { 0 }; acheck!(snd_mixer_open(&mut r, flags)).map(|_| Mixer(r))
45 }
46
47 pub fn attach(&mut self, name: &CStr) -> Result<()> {
48 acheck!(snd_mixer_attach(self.0, name.as_ptr())).map(|_| ())
49 }
50
51 pub fn load(&mut self) -> Result<()> {
52 acheck!(snd_mixer_load(self.0)).map(|_| ())
53 }
54
55 pub fn iter(&self) -> Iter<'_> {
56 Iter {
57 last_handle: ptr::null_mut(),
58 mixer: self
59 }
60 }
61
62 pub fn handle_events(&self) -> Result<u32> {
63 acheck!(snd_mixer_handle_events(self.0)).map(|x| x as u32)
64 }
65
66 pub fn wait(&self, timeout_ms: Option<u32>) -> Result<()> {
67 acheck!(snd_mixer_wait(self.0, timeout_ms.map(|x| x as c_int).unwrap_or(-1))).map(|_| ()) }
68}
69
70impl Drop for Mixer {
72 fn drop(&mut self) {
73 unsafe { alsa::snd_mixer_close(self.0) };
74 }
75}
76
77
78impl poll::Descriptors for Mixer {
79 fn count(&self) -> usize {
80 unsafe { alsa::snd_mixer_poll_descriptors_count(self.0) as usize }
81 }
82 fn fill(&self, p: &mut [pollfd]) -> Result<usize> {
83 let z = unsafe { alsa::snd_mixer_poll_descriptors(self.0, p.as_mut_ptr(), p.len() as c_uint) };
84 from_code("snd_mixer_poll_descriptors", z).map(|_| z as usize)
85 }
86 fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> {
87 let mut r = 0;
88 let z = unsafe { alsa::snd_mixer_poll_descriptors_revents(self.0, p.as_ptr() as *mut pollfd, p.len() as c_uint, &mut r) };
89 from_code("snd_mixer_poll_descriptors_revents", z).map(|_| poll::Flags::from_bits_truncate(r as c_short))
90 }
91}
92
93
94#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
100pub struct MilliBel(pub i64);
101
102impl MilliBel {
103 pub fn to_db(self) -> f32 { (self.0 as f32) / 100.0 }
104 pub fn from_db(db: f32) -> Self { MilliBel((db * 100.0) as i64) }
105}
106
107impl ops::Deref for MilliBel {
108 type Target = i64;
109 fn deref(&self) -> &i64 { &self.0 }
110}
111
112impl ops::Add for MilliBel {
113 type Output = MilliBel;
114 fn add(self, rhs: Self) -> Self { MilliBel(self.0 + rhs.0) }
115}
116
117impl ops::AddAssign for MilliBel {
118 fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
119}
120
121impl ops::Sub for MilliBel {
122 type Output = MilliBel;
123 fn sub(self, rhs: Self) -> Self { MilliBel(self.0 - rhs.0) }
124}
125
126impl ops::SubAssign for MilliBel {
127 fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
128}
129
130#[derive(Copy, Clone, Debug)]
132pub struct Elem<'a>{
133 handle: *mut alsa::snd_mixer_elem_t,
134 _mixer: &'a Mixer
135}
136
137#[derive(Copy, Clone, Debug)]
139pub struct Iter<'a>{
140 last_handle: *mut alsa::snd_mixer_elem_t,
141 mixer: &'a Mixer
142}
143
144impl<'a> Iterator for Iter<'a> {
145 type Item = Elem<'a>;
146
147 fn next(&mut self) -> Option<Elem<'a>> {
148 let elem = if self.last_handle.is_null() {
149 unsafe { alsa::snd_mixer_first_elem(self.mixer.0) }
150 } else {
151 unsafe { alsa::snd_mixer_elem_next(self.last_handle) }
152 };
153
154 if elem.is_null() {
155 None
156 } else {
157 self.last_handle = elem;
158 Some(Elem { handle: elem, _mixer: self.mixer})
159 }
160 }
161
162}
163
164#[derive(Debug)]
168pub struct SelemId([u8; SELEM_ID_SIZE]);
169
170impl SelemId {
171
172 pub fn new(name: &str, index: u32) -> SelemId {
173 let mut s = SelemId::empty();
174 s.set_name(&CString::new(name).unwrap());
175 s.set_index(index);
176 s
177 }
178
179 pub fn empty() -> SelemId {
182 assert!(unsafe { alsa::snd_mixer_selem_id_sizeof() } as usize <= SELEM_ID_SIZE);
183 SelemId(unsafe { mem::zeroed() })
185 }
186
187 #[inline]
190 fn as_ptr(&self) -> *mut alsa::snd_mixer_selem_id_t {
191 self.0.as_ptr() as *const _ as *mut alsa::snd_mixer_selem_id_t
192 }
193
194 pub fn get_name(&self) -> Result<&str> {
195 let c = unsafe { alsa::snd_mixer_selem_id_get_name(self.as_ptr()) };
196 from_const("snd_mixer_selem_id_get_name", c)
197 }
198
199 pub fn get_index(&self) -> u32 {
200 unsafe { alsa::snd_mixer_selem_id_get_index(self.as_ptr()) }
201 }
202
203 pub fn set_name(&mut self, name: &CStr) {
204 unsafe { alsa::snd_mixer_selem_id_set_name(self.as_ptr(), name.as_ptr()) };
205 }
206
207 pub fn set_index(&mut self, index: u32) {
208 unsafe { alsa::snd_mixer_selem_id_set_index(self.as_ptr(), index) };
209 }
210
211}
212
213#[derive(Debug)]
216pub struct Selem<'a>(Elem<'a>);
217
218impl<'a> Selem<'a> {
219 pub fn new(elem: Elem<'a>) -> Option<Selem<'a>> {
221 if unsafe { alsa::snd_mixer_elem_get_type(elem.handle) } == alsa::SND_MIXER_ELEM_SIMPLE
222 { Some(Selem(elem)) } else { None }
223 }
224
225 pub fn register(mixer: &mut Mixer) -> Result<()> {
227 acheck!(snd_mixer_selem_register(mixer.0, ptr::null_mut(), ptr::null_mut())).map(|_| ())
228 }
229
230 pub fn get_id(&self) -> SelemId {
231 let id = SelemId::empty();
232 unsafe { alsa::snd_mixer_selem_get_id(self.handle, id.as_ptr()) };
233 id
234 }
235
236 pub fn has_capture_volume(&self) -> bool {
237 unsafe { alsa::snd_mixer_selem_has_capture_volume(self.handle) > 0 }
238 }
239
240 pub fn has_capture_switch(&self) -> bool {
241 unsafe { alsa::snd_mixer_selem_has_capture_switch(self.handle) > 0 }
242 }
243
244 pub fn has_playback_volume(&self) -> bool {
245 unsafe { alsa::snd_mixer_selem_has_playback_volume(self.handle) > 0 }
246 }
247
248 pub fn has_playback_switch(&self) -> bool {
249 unsafe { alsa::snd_mixer_selem_has_playback_switch(self.handle) > 0 }
250 }
251
252 pub fn can_capture(&self) -> bool {
253 self.has_capture_volume() || self.has_capture_switch()
254 }
255
256 pub fn can_playback(&self) -> bool {
257 self.has_playback_volume() || self.has_playback_switch()
258 }
259
260 pub fn has_volume(&self) -> bool {
261 self.has_capture_volume() || self.has_playback_volume()
262 }
263
264 pub fn get_capture_volume_range(&self) -> (i64, i64) {
266 let mut min: c_long = 0;
267 let mut max: c_long = 0;
268 unsafe { alsa::snd_mixer_selem_get_capture_volume_range(self.handle, &mut min, &mut max) };
269 (min as i64, max as i64)
270 }
271
272 pub fn get_capture_db_range(&self) -> (MilliBel, MilliBel) {
274 let mut min: c_long = 0;
275 let mut max: c_long = 0;
276 unsafe { alsa::snd_mixer_selem_get_capture_dB_range(self.handle, &mut min, &mut max) };
277 (MilliBel(min as i64), MilliBel(max as i64))
278 }
279
280 pub fn get_playback_volume_range(&self) -> (i64, i64) {
282 let mut min: c_long = 0;
283 let mut max: c_long = 0;
284 unsafe { alsa::snd_mixer_selem_get_playback_volume_range(self.handle, &mut min, &mut max) };
285 (min as i64, max as i64)
286 }
287
288 pub fn get_playback_db_range(&self) -> (MilliBel, MilliBel) {
290 let mut min: c_long = 0;
291 let mut max: c_long = 0;
292 unsafe { alsa::snd_mixer_selem_get_playback_dB_range(self.handle, &mut min, &mut max) };
293 (MilliBel(min as i64), MilliBel(max as i64))
294 }
295
296 pub fn is_capture_mono(&self) -> bool {
297 unsafe { alsa::snd_mixer_selem_is_capture_mono(self.handle) == 1 }
298 }
299
300 pub fn is_playback_mono(&self) -> bool {
301 unsafe { alsa::snd_mixer_selem_is_playback_mono(self.handle) == 1 }
302 }
303
304 pub fn has_capture_channel(&self, channel: SelemChannelId) -> bool {
305 unsafe { alsa::snd_mixer_selem_has_capture_channel(self.handle, channel as i32) > 0 }
306 }
307
308 pub fn has_playback_channel(&self, channel: SelemChannelId) -> bool {
309 unsafe { alsa::snd_mixer_selem_has_playback_channel(self.handle, channel as i32) > 0 }
310 }
311
312 pub fn channel_name(channel: SelemChannelId) -> Result<&'static str> {
314 let c = unsafe { alsa::snd_mixer_selem_channel_name(channel as i32) };
315 from_const("snd_mixer_selem_channel_name", c)
316 }
317
318 pub fn get_playback_volume(&self, channel: SelemChannelId) -> Result<i64> {
319 let mut value: c_long = 0;
320 acheck!(snd_mixer_selem_get_playback_volume(self.handle, channel as i32, &mut value)).and_then(|_| Ok(value as i64))
321 }
322
323 pub fn get_playback_vol_db(&self, channel: SelemChannelId) -> Result<MilliBel> {
325 self.get_playback_volume(channel)
326 .and_then(|volume| self.ask_playback_vol_db(volume))
327 }
328
329 pub fn ask_playback_vol_db(&self, volume: i64) -> Result<MilliBel> {
331 let mut decibel_value: c_long = 0;
332 acheck!(snd_mixer_selem_ask_playback_vol_dB(self.handle, volume as c_long, &mut decibel_value))
333 .map(|_| MilliBel(decibel_value as i64))
334 }
335
336 pub fn ask_playback_db_vol(&self, db: MilliBel, dir: Round) -> Result<i64> {
338 let mut raw_volume: c_long = 0;
339 acheck!(snd_mixer_selem_ask_playback_dB_vol(self.handle, db.0 as c_long, dir as c_int, &mut raw_volume))
340 .map(|_| raw_volume as i64)
341 }
342
343 pub fn get_capture_volume(&self, channel: SelemChannelId) -> Result<i64> {
344 let mut value: c_long = 0;
345 acheck!(snd_mixer_selem_get_capture_volume(self.handle, channel as i32, &mut value)).map(|_| value as i64)
346 }
347
348 pub fn get_capture_vol_db(&self, channel: SelemChannelId) -> Result<MilliBel> {
350 self.get_capture_volume(channel)
351 .and_then(|volume| self.ask_capture_vol_db(volume))
352 }
353
354 pub fn ask_capture_vol_db(&self, volume: i64) -> Result<MilliBel> {
356 let mut decibel_value: c_long = 0;
357 acheck!(snd_mixer_selem_ask_capture_vol_dB (self.handle, volume as c_long, &mut decibel_value))
358 .map(|_| MilliBel(decibel_value as i64))
359 }
360
361 pub fn ask_capture_db_vol(&self, db: MilliBel, dir: Round) -> Result<i64> {
363 let mut raw_volume: c_long = 0;
364 acheck!(snd_mixer_selem_ask_capture_dB_vol(self.handle, db.0 as c_long, dir as c_int, &mut raw_volume))
365 .map(|_| raw_volume as i64)
366 }
367
368 pub fn set_playback_volume(&self, channel: SelemChannelId, value: i64) -> Result<()> {
369 acheck!(snd_mixer_selem_set_playback_volume(self.handle, channel as i32, value as c_long)).map(|_| ())
370 }
371
372 pub fn set_playback_volume_range(&self, min: i64, max: i64) -> Result<()> {
373 acheck!(snd_mixer_selem_set_playback_volume_range(self.handle, min as c_long, max as c_long)).map(|_| ())
374 }
375
376 pub fn set_playback_volume_all(&self, value: i64) -> Result<()> {
377 acheck!(snd_mixer_selem_set_playback_volume_all(self.handle, value as c_long)).map(|_| ())
378 }
379
380 pub fn set_playback_db(&self, channel: SelemChannelId, value: MilliBel, dir: Round) -> Result<()> {
381 acheck!(snd_mixer_selem_set_playback_dB(self.handle, channel as i32, *value as c_long, dir as c_int)).map(|_| ())
382 }
383
384 pub fn set_capture_db(&self, channel: SelemChannelId, value: MilliBel, dir: Round) -> Result<()> {
385 acheck!(snd_mixer_selem_set_capture_dB(self.handle, channel as i32, *value as c_long, dir as c_int)).map(|_| ())
386 }
387
388 pub fn set_playback_db_all(&self, value: MilliBel, dir: Round) -> Result<()> {
389 acheck!(snd_mixer_selem_set_playback_dB_all(self.handle, *value as c_long, dir as c_int)).map(|_| ())
390 }
391
392 pub fn set_capture_db_all(&self, value: MilliBel, dir: Round) -> Result<()> {
393 acheck!(snd_mixer_selem_set_capture_dB_all(self.handle, *value as c_long, dir as c_int)).map(|_| ())
394 }
395
396 pub fn set_capture_volume(&self, channel: SelemChannelId, value: i64) -> Result<()> {
397 acheck!(snd_mixer_selem_set_capture_volume(self.handle, channel as i32, value as c_long)).map(|_| ())
398 }
399
400 pub fn set_capture_volume_range(&self, min: i64, max: i64) -> Result<()> {
401 acheck!(snd_mixer_selem_set_capture_volume_range(self.handle, min as c_long, max as c_long)).map(|_| ())
402 }
403
404 pub fn set_capture_volume_all(&self, value: i64) -> Result<()> {
405 acheck!(snd_mixer_selem_set_capture_volume_all(self.handle, value as c_long)).map(|_| ())
406 }
407
408 pub fn set_playback_switch(&self, channel: SelemChannelId, value: i32) -> Result<()> {
409 acheck!(snd_mixer_selem_set_playback_switch(self.handle, channel as i32, value)).map(|_| ())
410 }
411
412 pub fn set_playback_switch_all(&self, value: i32) -> Result<()> {
413 acheck!(snd_mixer_selem_set_playback_switch_all(self.handle, value)).map(|_| ())
414 }
415
416 pub fn set_capture_switch(&self, channel: SelemChannelId, value: i32) -> Result<()> {
417 acheck!(snd_mixer_selem_set_capture_switch(self.handle, channel as i32, value)).map(|_| ())
418 }
419
420 pub fn set_capture_switch_all(&self, value: i32) -> Result<()> {
421 acheck!(snd_mixer_selem_set_capture_switch_all(self.handle, value)).map(|_| ())
422 }
423
424 pub fn get_playback_switch(&self, channel: SelemChannelId) -> Result<i32> {
425 let mut value: i32 = 0;
426 acheck!(snd_mixer_selem_get_playback_switch(self.handle, channel as i32, &mut value)).map(|_| value)
427 }
428
429 pub fn get_capture_switch(&self, channel: SelemChannelId) -> Result<i32> {
430 let mut value: i32 = 0;
431 acheck!(snd_mixer_selem_get_capture_switch(self.handle, channel as i32, &mut value)).map(|_| value)
432 }
433
434 pub fn is_enumerated(&self) -> bool {
435 unsafe { alsa::snd_mixer_selem_is_enumerated(self.handle) == 1 }
436 }
437
438 pub fn is_enum_playback(&self) -> bool {
439 unsafe { alsa::snd_mixer_selem_is_enum_playback(self.handle) == 1 }
440 }
441
442 pub fn is_enum_capture(&self) -> bool {
443 unsafe { alsa::snd_mixer_selem_is_enum_capture(self.handle) == 1 }
444 }
445
446 pub fn get_enum_items(&self) -> Result<u32> {
447 acheck!(snd_mixer_selem_get_enum_items(self.handle)).map(|v| v as u32)
448 }
449
450 pub fn get_enum_item_name(&self, idx: u32) -> Result<String> {
451 let mut temp = [0 as ::libc::c_char; 128];
452 acheck!(snd_mixer_selem_get_enum_item_name(self.handle, idx, temp.len()-1, temp.as_mut_ptr()))
453 .and_then(|_| from_const("snd_mixer_selem_get_enum_item_name", temp.as_ptr()))
454 .map(|v| v.into())
455 }
456
457 pub fn iter_enum(&self) -> Result<IterEnum<'_>> {
459 Ok(IterEnum(self, 0, self.get_enum_items()?))
460 }
461
462 pub fn get_enum_item(&self, channel: SelemChannelId) -> Result<u32> {
463 let mut temp = 0;
464 acheck!(snd_mixer_selem_get_enum_item(self.handle, channel as i32, &mut temp))
465 .map(|_| temp)
466 }
467
468 pub fn set_enum_item(&self, channel: SelemChannelId, idx: u32) -> Result<()> {
469 acheck!(snd_mixer_selem_set_enum_item(self.handle, channel as i32, idx))
470 .map(|_| ())
471 }
472}
473
474impl<'a> ops::Deref for Selem<'a> {
475 type Target = Elem<'a>;
476
477 fn deref(&self) -> &Elem<'a> {
479 &self.0
480 }
481}
482
483#[derive(Debug)]
484pub struct IterEnum<'a>(&'a Selem<'a>, u32, u32);
485
486impl<'a> Iterator for IterEnum<'a> {
487 type Item = Result<String>;
488 fn next(&mut self) -> Option<Self::Item> {
489 if self.1 >= self.2 { None }
490 else { self.1 += 1; Some(self.0.get_enum_item_name(self.1-1)) }
491 }
492}
493
494alsa_enum!(
495 SelemChannelId, ALL_SELEM_CHANNEL_ID[11],
497
498 Unknown = SND_MIXER_SCHN_UNKNOWN,
499 FrontLeft = SND_MIXER_SCHN_FRONT_LEFT,
500 FrontRight = SND_MIXER_SCHN_FRONT_RIGHT,
501 RearLeft = SND_MIXER_SCHN_REAR_LEFT,
502 RearRight = SND_MIXER_SCHN_REAR_RIGHT,
503 FrontCenter = SND_MIXER_SCHN_FRONT_CENTER,
504 Woofer = SND_MIXER_SCHN_WOOFER,
505 SideLeft = SND_MIXER_SCHN_SIDE_LEFT,
506 SideRight = SND_MIXER_SCHN_SIDE_RIGHT,
507 RearCenter = SND_MIXER_SCHN_REAR_CENTER,
508 Last = SND_MIXER_SCHN_LAST,
509);
510
511impl SelemChannelId {
512 pub fn mono() -> SelemChannelId { SelemChannelId::FrontLeft }
513}
514
515impl fmt::Display for SelemChannelId {
516 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517 write!(f, "{}", Selem::channel_name(*self).unwrap())
518 }
519}
520
521#[test]
522fn print_mixer_of_cards() {
523 extern crate std;
524 use std::{println, print};
525 use ::alloc::format;
526 use ::alloc::string::ToString;
527 use super::card;
528
529 for card in card::Iter::new().map(|c| c.unwrap()) {
530 println!("Card #{}: {} ({})", card.get_index(), card.get_name().unwrap(), card.get_longname().unwrap());
531
532 let mixer = Mixer::new(&format!("hw:{}", card.get_index()), false).unwrap();
533 for selem in mixer.iter().filter_map(|e| Selem::new(e)) {
534
535 let sid = selem.get_id();
536 println!("\tMixer element {},{}:", sid.get_name().unwrap(), sid.get_index());
537
538 if selem.has_volume() {
539 print!("\t Volume limits: ");
540 if selem.has_capture_volume() {
541 let (vmin, vmax) = selem.get_capture_volume_range();
542 let (mbmin, mbmax) = selem.get_capture_db_range();
543 print!("Capture = {} - {}", vmin, vmax);
544 print!(" ({} dB - {} dB)", mbmin.to_db(), mbmax.to_db());
545 }
546 if selem.has_playback_volume() {
547 let (vmin, vmax) = selem.get_playback_volume_range();
548 let (mbmin, mbmax) = selem.get_playback_db_range();
549 print!("Playback = {} - {}", vmin, vmax);
550 print!(" ({} dB - {} dB)", mbmin.to_db(), mbmax.to_db());
551 }
552 println!();
553 }
554
555 if selem.is_enumerated() {
556 print!("\t Valid values: ");
557 for v in selem.iter_enum().unwrap() { print!("{}, ", v.unwrap()) };
558 print!("\n\t Current values: ");
559 for v in SelemChannelId::all().iter().filter_map(|&v| selem.get_enum_item(v).ok()) {
560 print!("{}, ", selem.get_enum_item_name(v).unwrap());
561 }
562 println!();
563 }
564
565 if selem.can_capture() {
566 print!("\t Capture channels: ");
567 if selem.is_capture_mono() {
568 print!("Mono");
569 } else {
570 for channel in SelemChannelId::all() {
571 if selem.has_capture_channel(*channel) { print!("{}, ", channel) };
572 }
573 }
574 println!();
575 print!("\t Capture volumes: ");
576 for channel in SelemChannelId::all() {
577 if selem.has_capture_channel(*channel) { print!("{}: {} ({} dB), ", channel,
578 match selem.get_capture_volume(*channel) {Ok(v) => format!("{}", v), Err(_) => "n/a".to_string()},
579 match selem.get_capture_vol_db(*channel) {Ok(v) => format!("{}", v.to_db()), Err(_) => "n/a".to_string()}
580 );}
581 }
582 println!();
583 }
584
585 if selem.can_playback() {
586 print!("\t Playback channels: ");
587 if selem.is_playback_mono() {
588 print!("Mono");
589 } else {
590 for channel in SelemChannelId::all() {
591 if selem.has_playback_channel(*channel) { print!("{}, ", channel) };
592 }
593 }
594 println!();
595 if selem.has_playback_volume() {
596 print!("\t Playback volumes: ");
597 for channel in SelemChannelId::all() {
598 if selem.has_playback_channel(*channel) { print!("{}: {} / {}dB, ",
599 channel,
600 match selem.get_playback_volume(*channel) {Ok(v) => format!("{}", v), Err(_) => "n/a".to_string()},
601 match selem.get_playback_vol_db(*channel) {Ok(v) => format!("{}", v.to_db()), Err(_) => "n/a".to_string()}
602 );}
603 }
604 println!();
605 }
606 }
607 }
608 }
609}
610
611#[test]
612#[ignore]
613fn get_and_set_playback_volume() {
614 extern crate std;
615
616 let mixer = Mixer::new("hw:1", false).unwrap();
617 let selem = mixer.find_selem(&SelemId::new("Master", 0)).unwrap();
618
619 let (rmin, rmax) = selem.get_playback_volume_range();
620 let mut channel = SelemChannelId::mono();
621 for c in SelemChannelId::all().iter() {
622 if selem.has_playback_channel(*c) { channel = *c; break }
623 }
624 std::println!("Testing on {} with limits {}-{} on channel {}", selem.get_id().get_name().unwrap(), rmin, rmax, channel);
625
626 let old: i64 = selem.get_playback_volume(channel).unwrap();
627 let new: i64 = rmax / 2;
628 assert_ne!(new, old);
629
630 std::println!("Changing volume of {} from {} to {}", channel, old, new);
631 selem.set_playback_volume(channel, new).unwrap();
632 let mut result: i64 = selem.get_playback_volume(channel).unwrap();
633 assert_eq!(new, result);
634
635 selem.set_playback_volume(channel, old).unwrap();
637 result = selem.get_playback_volume(channel).unwrap();
638 assert_eq!(old, result);
639}
640
641#[test]
642#[ignore]
643fn get_and_set_capture_volume() {
644 extern crate std;
645
646 let mixer = Mixer::new("hw:1", false).unwrap();
647 let selem = mixer.find_selem(&SelemId::new("Capture", 0)).unwrap();
648
649 let (rmin, rmax) = selem.get_capture_volume_range();
650 let mut channel = SelemChannelId::mono();
651 for c in SelemChannelId::all().iter() {
652 if selem.has_playback_channel(*c) { channel = *c; break }
653 }
654 std::println!("Testing on {} with limits {}-{} on channel {}", selem.get_id().get_name().unwrap(), rmin, rmax, channel);
655
656 let old: i64 = selem.get_capture_volume(channel).unwrap();
657 let new: i64 = rmax / 2;
658 assert_ne!(new, old);
659
660 std::println!("Changing volume of {} from {} to {}", channel, old, new);
661 selem.set_capture_volume(channel, new).unwrap();
662 let mut result: i64 = selem.get_capture_volume(channel).unwrap();
663 assert_eq!(new, result);
664
665 selem.set_capture_volume(channel, old).unwrap();
667 result = selem.get_capture_volume(channel).unwrap();
668 assert_eq!(old, result);
669}
670
671
672#[test]
673fn print_sizeof() {
674 extern crate std;
675 let selemid = unsafe { alsa::snd_mixer_selem_id_sizeof() } as usize;
676
677 assert!(selemid <= SELEM_ID_SIZE);
678 std::println!("Selem id: {}", selemid);
679}