volume_linux.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // +build !windows,!darwin
  2. /*
  3. * Copied from https://github.com/itchyny/volume-go, MIT License
  4. */
  5. package Sound
  6. import (
  7. "errors"
  8. "os/exec"
  9. "regexp"
  10. "strconv"
  11. "strings"
  12. )
  13. var useAmixer bool
  14. func init() {
  15. if _, err := exec.LookPath("pactl"); err != nil {
  16. useAmixer = true
  17. }
  18. }
  19. func cmdEnv() []string {
  20. return []string{"LANG=C", "LC_ALL=C"}
  21. }
  22. func getVolumeCmd() []string {
  23. if useAmixer {
  24. return []string{"amixer", "get", "Master"}
  25. }
  26. return []string{"pactl", "list", "sinks"}
  27. }
  28. var volumePattern = regexp.MustCompile(`\d+%`)
  29. func parseVolume(out string) (int, error) {
  30. lines := strings.Split(out, "\n")
  31. for _, line := range lines {
  32. s := strings.TrimLeft(line, " \t")
  33. if useAmixer && strings.Contains(s, "Playback") && strings.Contains(s, "%") ||
  34. !useAmixer && strings.HasPrefix(s, "Volume:") {
  35. volumeStr := volumePattern.FindString(s)
  36. return strconv.Atoi(volumeStr[:len(volumeStr)-1])
  37. }
  38. }
  39. return 0, errors.New("no volume found")
  40. }
  41. func setVolumeCmd(volume int) []string {
  42. if useAmixer {
  43. return []string{"amixer", "set", "Master", strconv.Itoa(volume) + "%"}
  44. }
  45. return []string{"pactl", "set-sink-volume", "0", strconv.Itoa(volume) + "%"}
  46. }
  47. func increaseVolumeCmd(diff int) []string {
  48. var sign string
  49. if diff >= 0 {
  50. sign = "+"
  51. } else if useAmixer {
  52. diff = -diff
  53. sign = "-"
  54. }
  55. if useAmixer {
  56. return []string{"amixer", "set", "Master", strconv.Itoa(diff) + "%" + sign}
  57. }
  58. return []string{"pactl", "--", "set-sink-volume", "0", sign + strconv.Itoa(diff) + "%"}
  59. }
  60. func getMutedCmd() []string {
  61. if useAmixer {
  62. return []string{"amixer", "get", "Master"}
  63. }
  64. return []string{"pactl", "list", "sinks"}
  65. }
  66. func parseMuted(out string) (bool, error) {
  67. lines := strings.Split(out, "\n")
  68. for _, line := range lines {
  69. s := strings.TrimLeft(line, " \t")
  70. if useAmixer && strings.Contains(s, "Playback") && strings.Contains(s, "%") ||
  71. !useAmixer && strings.HasPrefix(s, "Mute: ") {
  72. if strings.Contains(s, "[off]") || strings.Contains(s, "yes") {
  73. return true, nil
  74. } else if strings.Contains(s, "[on]") || strings.Contains(s, "no") {
  75. return false, nil
  76. }
  77. }
  78. }
  79. return false, errors.New("no muted information found")
  80. }
  81. func muteCmd() []string {
  82. if useAmixer {
  83. return []string{"amixer", "-D", "pulse", "set", "Master", "mute"}
  84. }
  85. return []string{"pactl", "set-sink-mute", "0", "1"}
  86. }
  87. func unmuteCmd() []string {
  88. if useAmixer {
  89. return []string{"amixer", "-D", "pulse", "set", "Master", "unmute"}
  90. }
  91. return []string{"pactl", "set-sink-mute", "0", "0"}
  92. }