1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Alsa audio helper functions.
//!
//! This mod wraps around a few low-level alsa functions and abstracts
//! out the details we don't care about.


use alsa::card::Card;
use alsa::mixer::{Mixer, Selem, Elem};
use alsa;
use errors::*;
use libc::c_int;



/// Get the default alsa card. This is the one with the ID `0`.
pub fn get_default_alsa_card() -> Card {
    return get_alsa_card_by_id(0);
}


/// Get an alsa card corresponding to the given ID.
pub fn get_alsa_card_by_id(index: c_int) -> Card {
    return Card::new(index);
}


/// Get all available alsa cards.
pub fn get_alsa_cards() -> alsa::card::Iter {
    return alsa::card::Iter::new();
}


/// Get the first playable alsa card.
pub fn get_first_playable_alsa_card() -> Result<Card> {
    for m_card in get_alsa_cards() {
        match m_card {
            Ok(card) => {
                if alsa_card_has_playable_selem(&card) {
                    return Ok(card);
                }
            }
            _ => (),
        }
    }

    bail!("No playable alsa card found!")
}


/// Get the names of all playable alsa cards.
pub fn get_playable_alsa_card_names() -> Vec<String> {
    let mut vec = vec![];
    for m_card in get_alsa_cards() {
        match m_card {
            Ok(card) => {
                if alsa_card_has_playable_selem(&card) {
                    let m_name = card.get_name();
                    if m_name.is_ok() {
                        vec.push(m_name.unwrap())
                    }
                }
            }
            _ => (),
        }
    }

    return vec;
}


/// Get an alsa card by the given name.
pub fn get_alsa_card_by_name(name: String) -> Result<Card> {
    for r_card in get_alsa_cards() {
        let card = r_card?;
        let card_name = card.get_name()?;
        if name == card_name {
            return Ok(card);
        }
    }
    bail!("Not found a matching card named {}", name);
}


/// Check whether the given alsa card as a playable `Selem`.
pub fn alsa_card_has_playable_selem(card: &Card) -> bool {
    let mixer = try_wr!(get_mixer(&card), false);
    for selem in get_playable_selems(&mixer) {
        if selem_is_playable(&selem) {
            return true;
        }
    }
    return false;
}


/// Get the `Mixer` for the given alsa card.
pub fn get_mixer(card: &Card) -> Result<Mixer> {
    return Mixer::new(&format!("hw:{}", card.get_index()), false).from_err();
}


/// Get the `Selem` from the given `Elem`.
pub fn get_selem(elem: Elem) -> Selem {
    /* in the ALSA API, there are currently only simple elements,
     * so this unwrap() should be safe.
     *http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html#enum-members */
    return Selem::new(elem).unwrap();
}


/// Get all playable `Selem`s.
pub fn get_playable_selems(mixer: &Mixer) -> Vec<Selem> {
    let mut v = vec![];
    for s in mixer.iter().map(get_selem).filter(selem_is_playable) {
        v.push(s);
    }
    return v;
}


/// Get the first playable `Selem`.
pub fn get_first_playable_selem(mixer: &Mixer) -> Result<Selem> {
    for s in mixer.iter().map(get_selem).filter(selem_is_playable) {
        return Ok(s);
    }

    bail!("No playable Selem found!")
}


/// Get the names from all playable `Selem`s.
pub fn get_playable_selem_names(mixer: &Mixer) -> Vec<String> {
    let mut vec = vec![];
    for selem in get_playable_selems(mixer) {
        let n = selem.get_id().get_name().map(|y| String::from(y));
        match n {
            Ok(name) => vec.push(name),
            _ => (),
        }
    }

    return vec;
}


/// Get a playable `Selem` by the given name.
pub fn get_playable_selem_by_name(mixer: &Mixer,
                                  name: String)
                                  -> Result<Selem> {
    for selem in get_playable_selems(mixer) {
        let n = selem.get_id()
            .get_name()
            .map(|y| String::from(y))?;

        if n == name {
            return Ok(selem);
        }
    }
    bail!("Not found a matching playable selem named {}", name);
}


/// Check whether the given `Selem` is playable.
pub fn selem_is_playable(selem: &Selem) -> bool {
    return selem.has_playback_volume();
}