hathoris/alsacontrol/cardcontrol.go

204 lines
4.4 KiB
Go

package alsa
import (
"bufio"
"fmt"
"os/exec"
"strconv"
"strings"
)
type CardControl struct {
NumID int64
Interface string
Name string
Type string
Access string
NValues int64
Min int64
Max int64
Step int64
DBScale CardControldBScale
Values []string
Items []string
}
func (cc *CardControl) parseAmixerField(key, value string) (err error) {
switch key {
case "numid":
cc.NumID, err = strconv.ParseInt(value, 10, 64)
case "iface":
cc.Interface = value
case "name":
cc.Name = strings.TrimPrefix(strings.TrimSuffix(value, "'"), "'")
case "type":
cc.Type = value
case "access":
cc.Access = value
case "values":
cc.NValues, err = strconv.ParseInt(value, 10, 64)
case "min":
cc.Min, err = strconv.ParseInt(value, 10, 64)
case "max":
cc.Max, err = strconv.ParseInt(value, 10, 64)
case "step":
cc.Step, err = strconv.ParseInt(value, 10, 64)
}
return
}
func (cc *CardControl) ToCardControlState() *CardControlState {
ccs := &CardControlState{
NumID: cc.NumID,
Type: cc.Type,
Name: cc.Name,
RW: strings.HasPrefix(cc.Access, "rw"),
Items: cc.Items,
}
if cc.DBScale.Min != 0 || cc.DBScale.Step != 0 {
ccs.DBScale = &cc.DBScale
}
// Convert values
for _, v := range cc.Values {
if cc.Type == "INTEGER" || cc.Type == "ENUMERATED" {
if tmp, err := strconv.ParseFloat(v, 10); err == nil {
ccs.Current = append(ccs.Current, tmp)
}
} else if cc.Type == "BOOLEAN" {
if v == "on" {
ccs.Current = append(ccs.Current, true)
} else {
ccs.Current = append(ccs.Current, false)
}
}
}
ccs.Min = cc.Min
ccs.Max = cc.Max
return ccs
}
type CardControldBScale struct {
Min float64
Step float64
Mute int64 `json:",omitempty"`
}
func (cc *CardControldBScale) parseAmixerField(key, value string) (err error) {
switch key {
case "min":
cc.Min, err = strconv.ParseFloat(strings.TrimSuffix(value, "dB"), 10)
case "step":
cc.Step, err = strconv.ParseFloat(strings.TrimSuffix(value, "dB"), 10)
case "mute":
cc.Mute, err = strconv.ParseInt(value, 10, 64)
}
return
}
type CardControlState struct {
NumID int64
Name string
Type string
RW bool `json:"RW,omitempty"`
Min int64
Max int64
DBScale *CardControldBScale `json:",omitempty"`
Current []interface{} `json:"values,omitempty"`
Items []string `json:"items,omitempty"`
}
func ParseAmixerContent(cardId string) ([]*CardControl, error) {
cardIdType := "-D"
if _, err := strconv.Atoi(cardId); err == nil {
cardIdType = "-c"
}
cmd := exec.Command("amixer", cardIdType, cardId, "-M", "contents")
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
var ret []*CardControl
fscanner := bufio.NewScanner(stdout)
for fscanner.Scan() {
line := fscanner.Text()
if strings.HasPrefix(line, " ; Item #") {
cc := ret[len(ret)-1]
cc.Items = append(cc.Items, strings.TrimSuffix(line[strings.Index(line, "'")+1:], "'"))
} else if strings.HasPrefix(line, " :") {
cc := ret[len(ret)-1]
line = strings.TrimPrefix(line, " : ")
kv := strings.SplitN(line, "=", 2)
if kv[0] == "values" {
cc.Values = strings.Split(kv[1], ",")
}
} else if strings.HasPrefix(line, " |") || strings.HasPrefix(line, " |") {
cc := ret[len(ret)-1]
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "| dBscale-") {
line = strings.TrimPrefix(line, "| dBscale-")
fields := strings.Split(line, ",")
var scale CardControldBScale
for _, field := range fields {
kv := strings.SplitN(field, "=", 2)
scale.parseAmixerField(kv[0], kv[1])
}
cc.DBScale = scale
}
} else {
var cc *CardControl
if strings.HasPrefix(line, "numid=") {
cc = &CardControl{}
ret = append(ret, cc)
} else {
cc = ret[len(ret)-1]
line = strings.TrimPrefix(line, " ; ")
}
fields := strings.Split(line, ",")
for _, field := range fields {
kv := strings.SplitN(field, "=", 2)
cc.parseAmixerField(kv[0], kv[1])
}
}
}
err = cmd.Wait()
return ret, err
}
func (cc *CardControl) CsetAmixer(cardId string, values ...string) error {
opts := []string{
"-c",
cardId,
"-M",
"cset",
fmt.Sprintf("numid=%d", cc.NumID),
}
opts = append(opts, strings.Join(values, ","))
cmd := exec.Command("amixer", opts...)
if err := cmd.Start(); err != nil {
return err
}
return cmd.Wait()
}