Как узнать, подключены ли наушники, для сценария оболочки?

Вопрос или проблема

Я пишу свой собственный статус для i3/Sway, который показывает индикатор громкости, и столкнулся с проблемой.

Мне хотелось бы узнать, существует ли стандартный способ с использованием стандартных инструментов Linux — возможно, ALSA или sysfs — чтобы определить, подключены ли наушники или нет? Я предпочел бы сделать это таким образом, на случай если я когда-либо захочу переключиться с Pipewire на обычный JACK или что-то еще.

Я размещу сегмент из этого «полуработающего» решения, которое мне удалось найти в Интернете (извините, но я не могу вспомнить, кто выложил это, чтобы отдать должное этому человеку).

has_headset() {
    grep -A4 -ri "Headphone Playback Switch" /proc/asound/card*/* |
        grep "Amp-Out vals.*\[0x00\]*"
}

Эта функция has_headset() в какой-то степени работает, но проблема в том, что если наушники подключены И отключены, она не сработает. Не уверен, что означают значения “Amp-Out vals”. Кажется, что это [0x80] [0x80], когда наушники отключены, и [0x00] [0x00], когда наушники подключены и не отключены.

Я использую POSIX sh, но решения, написанные специально для Bash, также приветствуются!

has_headphone() {
  for card in /proc/asound/card*; do
    amixer -c"${card##*card}" cget 'iface=CARD,name=Headphone Jack'
  done 2> /dev/null | grep -qw values=on
}

У меня это работает с alsa-utils 1.2.12 на Debian trixie (testing) и Аудиоустройство: Intel Corporation 7 Series/C216 Chipset Family High Definition Audio Controller (rev 04).

Смотрите также amixer -c0 contents, чтобы увидеть все элементы управления на карте 0, если имя отличается от Headphone Jack в вашем случае.

Ноутбук, на котором я это тестирую, имеет комбинированный TRRS-разъем для наушников и микрофона, но я все равно вижу дополнительный элемент управления Mic Jack, который переключается на on, когда я подключаю гарнитуру, но не наушники без микрофона (разъем TRS), поэтому для has_headset, который проверяет, подключены ли одновременно наушники и микрофон к одной и той же карте, вы можете сделать:

jack_connected() {
  amixer -c"$1" cget "iface=CARD,name=$2 Jack" 2> /dev/null |
    grep -qw values=on
}

has_headset() {
  for card in /proc/asound/card*; do
    card=${card##*card}
    jack_connected "$card" Headphone &&
      jack_connected "$card" Mic &&
      return
  done
  false
}

Обратите внимание, что под strace я вижу, как amixer выполняет:

openat(AT_FDCWD, "/dev/snd/controlC0", O_RDWR|O_CLOEXEC) = 3
[...]
ioctl(3, SNDRV_CTL_IOCTL_ELEM_INFO, 0x7ffc2fdc3020) = 0

Так что информация не получается из /proc и не из /sys.

Ответ или решение

Для обнаружения подключения наушников в вашем пользовательском статусе для i3/Sway с использованием стандартных инструментов Linux, таких как ALSA, можно воспользоваться функциональностью, предоставляемой командой amixer. Этот способ будет независимым от используемой звуковой системы, будь то Pipewire, JACK или ALSA, и, как следствие, обеспечит большую гибкость в будущем.

1. Определение состояния наушников

Для начала следует создать функцию, называемую has_headphone(), которая будет проверять, подключены ли наушники. Эта функция будет обращаться к управляющему интерфейсу ALSA и искать элемент управления, связанный с разъемом наушников. Используя команду amixer, можно выполнить следующие шаги:

has_headphone() {
  for card in /proc/asound/card*; do
    # Извлечение номера карты
    card_num="${card##*card}"

    # Проверка состояния наушников
    if amixer -c"$card_num" cget 'iface=CARD,name=Headphone Jack' 2>/dev/null | grep -qw values=on; then
      return 0  # Наушники подключены
    fi
  done
  return 1  # Наушники не подключены
}

2. Обработка различных типов аудиоразъемов

Если у вас есть комбинированный разъем для наушников и микрофона (TRRS), полезно также проверять, подключен ли микрофон. Для этого можно расширить функцию для проверки обоих разъемов:

jack_connected() {
  amixer -c"$1" cget "iface=CARD,name=$2 Jack" 2>/dev/null | grep -qw values=on
}

has_headset() {
  for card in /proc/asound/card*; do
    card_num="${card##*card}"

    if jack_connected "$card_num" Headphone && jack_connected "$card_num" Mic; then
      return 0  # Наушники и микрофон подключены
    fi
  done
  return 1  # Наушники или микрофон не подключены
}

3. Исполнение кода и взаимодействие со статусом

Теперь, когда функции определены, вы можете использовать их в основном скрипте, чтобы отображать соответствующий статус в вашем инструменте (например, в строке состояния):

if has_headphone; then
  echo "Наушники подключены"
else
  echo "Наушники не подключены"
fi

if has_headset; then
  echo "Наушники и микрофон подключены"
else
  echo "Наушники или микрофон не подключены"
fi

4. Заключительные замечания

Использование функций amixer в вашем сценарии на POSIX sh или Bash предоставит вам стабильный и совместимый способ определения состояния наушников без зависимости от конкретной звуковой подсистемы. Чтобы убедиться, что скрипт работает корректно на различных аудиокартах, рекомендуется выполнить тестирование в разных окружениях и с разными устройствами.

Следуя вышеизложенным рекомендациям, вы сможете эффективно отслеживать состояние подключения наушников и интегрировать этот функционал в ваш кастомный статус для менеджера окон, что повысит интерфейс вашего программного обеспечения и улучшит пользовательский опыт.

Оцените материал
Добавить комментарий

Капча загружается...