Путеводитель по джунглям звуковых API в Linux

Оригинал: A Guide Through The Linux Sound API Jungle
Автор: Lennart Poettering
Дата публикации: 24 сентября 2008 г.
Перевод: Максим Белозеров
Дата перевода: 25 августа 2009 г.

Во время миниконференции, посвященной теме аудио, на конференции Linux Plumbers выяснилась одна вещь: программистам часто трудно решить, какие из звуковых API для каких целей использовать при создании аудиопрограмм для Linux. Давайте попробуем разобраться в этих джунглях:

Что вы хотите сделать?

  • Я хочу написать еще один медиаплеер!
  • Используйте GStreamer! (Но если вы собираетесь писать только для KDE, тогда используйте альтернативный вариант — Phonon).

  • Я хочу добавить в свое приложение звуковые оповещения для событий!
  • Используйте libcanberra, устанавливайте звуковые файлы в соответствии со спецификациями XDG по звуковым темам и их именованию (но если вы собираетесь писать только для KDE, тогда как альтернативу можно использовать KNotify, хотя у него немного другие задачи).

  • Я хочу создавать профессиональные аудиоредакторы, программы для звукозаписи, работы с MIDI и синтезаторы!
  • Используйте JACK и (или) полный интерфейс ALSA.

  • Мне нужно простое воспроизведение и захват PCM-аудио! 1)
  • Используйте безопасную часть ALSA.

  • Хочу добавить звук к своей игре!
  • Используйте звуковой API из SDL для полноэкранных игр, а libcanberra для простых игр со стандартным пользовательским интерфейсом типа Gtk+.

  • Хочу написать микшер!
  • Используйте уровень, с которым собираетесь непосредственно работать: если хотите обеспечить поддержку усовершенствованных программных микшеров, используйте API управления громкостью PulseAudio. Чтобы обеспечить поддержку аппаратных микшеров, используйте API микшера ALSA.

  • Я хочу писать аудиоприложения промежуточного уровня!
  • Используйте полный стек ALSA.

  • Мне нужно написать аудиоприложения для встроенных систем!
  • Для технического применения обычно подходит безопасная часть ALSA, но все зависит от конкретного случая.

Хотите узнать больше о различных звуковых API?

GStreamer

GStreamer — стандарт де-факто для систем управления медиапотоками для рабочих станций Linux. Он поддерживает кодирование и декодирование аудио- и видеопотоков. Его можно применять для самых разных целей от простого воспроизведения аудиофайлов до сложных систем вещания по сети. GStreamer поддерживает широкий диапазон кодеков и звуковых подсистем. GStreamer не очень подходит для воспроизведения простого PCM и для приложений, работающих с малой задержкой или в реальном масштабе времени. GStreamer переносим и может использоваться не только в Linux. Среди поддерживаемых звуковых подсистем — ALSA, OSS и PulseAudio. [Справочник и руководство по программированию]

libcanberra

libcanberra — звуковой API для абстрактных событий. В нем реализованы спецификации XDG по звуковым темам и их именованию. libcanberra разработана для GNOME, но сама по себе не зависит от GNOME, Gtk или GLib и может использоваться в других окружениях рабочего стола. Помимо простого интерфейса для воспроизведения аудиофайлов libcanberra обеспечивает кэширование (что весьма полезно для сетевых тонких клиентов) и позволят передавать различные метаданные звуковым подсистемам, что можно использовать для создания дополнительных удобств для пользователя (например, для озвучивания событий позиционирования) и для улучшения восприятия. libcanberra поддерживает различные звуковые подсистемы и может портироваться на системы, отличные от Linux. Среди поддерживаемых звуковых подсистем — ALSA, OSS, PulseAudio и GStreamer. [Справочник по API]

JACK

JACK — звуковая систем для коммутации профессиональных аудиоприложений и аппаратных выходов. Основной акцент делается на низких задержках сигнала и коммутации между приложениями. Эта система не нужна для обычного рабочего стола или для встраиваемых систем. От этого API не будет пользы, если вам требуется простое воспроизведение PCM. JACK поддерживает различные звуковые подсистемы, но лучше работает с ALSA. JACK можно переносить на другие ОС. Среди поддерживаемых звуковых подсистем — ALSA и OSS. [Справочник по API]

Полный интерфейс ALSA

ALSA — это API для воспроизведения и записи PCM-аудио в Linux. ALSA в основном работает с оборудованием, хотя поддерживаются и другие звуковые подсистемы (с некоторыми ограничениями, см. ниже). Название ALSA применяется как к драйверам ядра Linux, так и к библиотеке пространства пользователя, использующей их. Библиотека ALSA полнофункциональная и переносимая (с некоторыми ограничениями). Полный API ALSA может показаться очень сложным и большим. Зато он поддерживает практически все функции современного звукового оборудования. Часть функциональности программного интерфейса ALSA ограничивается поддержкой оборудования ядром Linux (в отличие от программных звуковых серверов и драйверов пользовательского пространства, таких как аудио для Bluetooth и FireWire) и драйверами для Linux. [Справочник по API]

Безопасная часть ALSA

Только часть полного API ALSA работает со всеми звуковыми подсистемами, поддерживаемыми ALSA. Рекомендуется придерживаться этойбезопасной части, если вы пишете программы для ALSA, которые должны быть переносимыми, не устаревающими и совместимыми со звуковыми серверами, Bluetooth-аудио и FireWire-аудио. Ниже подробно описывается, какие из функций ALSA считаются безопасными.Безопасная часть API ALSA — подходящая абстракция для переносимого базового воспроизведения и записи PCM, которая используется не только для устройств, поддерживаемых драйвером ядра ALSA. Среди поддерживаемых звуковых подсистем — устройства драйвера ядра ALSA, OSS, PulseAudio и JACK.

Phonon и KNotify

Phonon — высокоуровневая абстракция для систем потокового воспроизведения, таких как GStreamer, но этим ее функциональность не ограничивается. Поддерживается несколько звуковых подсистем. KNotify — система для “оповещений” в широком смысле, не только звуковых. Однако в ней пока не поддерживаются спецификации XDG по звуковым темам и их именованию, а также не поддерживается кэширование или передача метаданных оповещения звуковой подсистеме нижнего уровня. KNotify поддерживает разные подсистемы для воспроизведения звука через Phonon. Оба API специфичны для KDE/Qt и для приложений за пределами KDE/Qt их лучше не использовать. [Справочник по API Phonon] [Справочник по API KNotify]

SDL

SDL — переносимый API, используемый в основном для разработки полноэкранных игр. Среди прочего он включает в себя и переносимый аудиоинтерфейс. Среди звуковых подсистем, поддерживаемых SDL — OSS, PulseAudio и ALSA. [Справочник по API]

PulseAudio

PulseAudio — звуковая система для Linux-десктопов и встроенных окружений, работающая в пространстве пользователя, обычно поверх ALSA. PulseAudio поддерживает сквозной тракт передачи, раздельный уровень громкости для разных приложений, озвучивание пространственных оповещений, позволяет на лету переключать звуковые потоки между устройствами и выполнять многие другие высокоуровневые операции. PulseAudio добавляет к аудиостеку Linux модель бесперебойного воспроизведения (см. glitch-free). PulseAudio не подходит для профессиональных систем работы с аудио. PulseAudio можно портировать на системы, отличные от Linux. В PulseAudio есть собственный API, а также поддержка безопасной части ALSA, а также ограниченная, основанная на LD_PRELOAD совместимость с OSS. Среди поддерживаемых PulseAudio звуковых подсистем — OSS и ALSA. Также есть возможность взаимодействия с JACK. [Справочник по API]

OSS

Open Sound System — низкоуровневый PCM API, поддерживаемый многими Unix-системами, в том числе и Linux. Сначала это была стандартная аудиосистема Linux, современные ядра Linux поддерживают третью версию API, OSS3. OSS3 считается устаревшим и был полностью заменен на ALSA. Уже появился OSS4, преемник OSS3, но практически не играет роли для Linux и не поддерживается в стандартных ядрах и распространенных дистрибутивах. OSS API работает на низком уровне, на основе прямых обращений к интерфейсам ядра с помощью ioctl(). Поэтому его неудобно использовать и практически нельзя виртуализировать для использования в аудиосистемах вне ядра, таких как звуковые серверы (например PulseAudio) или драйверы пространства пользователя (например Bluetooth- или FireWire-аудио). Модель с учетом задержек в OSS3 вообще нельзя верно преобразовать для программных звуковых серверов, а также возникают проблемы с оборудованием, подключенным не по шине PCI, например по USB. Кроме того, OSS не конвертирует, не перераспределяет или перекодирует типы дискретизации при необходимости. Это значит, что клиентские приложения, которые должны поддерживать OSS, обязаны содержать полный набор утилит для конвертации, переназначения и перекодирования на тот случай, если оборудование не поддерживает аппаратно требуемые параметры дискретизации. Среди современных звуковых карт часто встречается поддержка только S32LE на 48 кГц. Если предполагается, что клиентское приложение для OSS всегда воспроизводит звук в с дискретизацией S16LE на 44,1 кГц, ничего не выйдет. OSS3 можно портировать на другие Unix-совместимые ОС, но с учетом некоторых различий. В OSS также нет нормальной поддержки многоканального звука и другой функциональности современных аудиосистем. OSS устарел, его не следует использовать для новых приложений. В ALSA и PulseAudio есть ограниченная совместимость с OSS, основанная на LD_PRELOAD. [Руководство по программированию]

Все звуковые системы и API, перечисленные выше, поддерживаются во всех популярных современных дистрибутивах. Для поддержки libcanberra может потребоваться последний выпуск вашего дистрибутива для разработчиков.

Все звуковые системы и API, перечисленные выше, подходят для разработки коммерческих приложений с закрытым кодом, так как они лицензированы под LGPL или более либеральными лицензиями, либо в клиентскую часть не включаются библиотеки.

Когда и где стоит использовать тот или иной API?

GStreamer

GStreamer хорошо подходит для высокоуровневых задач. Например, если вам надо воспроизвести аудиофайл или видеопоток, не заботясь о несущественных деталях на уровне кодеков или PCM.

libcanberra

libcanberra лучше всего подходит для озвучивания ввода в пользовательских интерфейсах или для воспроизведения простых звуковых файлов для оповещений.

JACK

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

Полный интерфейс ALSA

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

Безопасная часть ALSA

Безопасный интерфейс ALSA хорошо подходит для программ, которые занимаются записью/воспроизведением простых PCM-данных с аппаратных устройств или программных звуковых подсистем.

Phonon и KNotify

Phonon и KNotify стоит использовать только в приложениях KDE/Qt для высокоуровневого воспроизведения медиаданных и для простых звуковых оповещений соответственно.

SDL

SDL подходит для полноэкранных игр.

PulseAudio

На данный момент API PulseAudio следует использовать только для приложений, которые должны обеспечивать функциональность, специфичную для звукового сервера (например, микшеров) или если уровень абстракций вывода PCM уже реализован в приложении и имеет смысл добавить поддержку PulseAudio для минимизации количества уровней в аудиостеке.

OSS

OSS не следует использовать для новых программ.

Хотите узнать больше о безопасной части ALSA?

Вот список того, что следует и не следует делать, если вы хотите, чтобы ваши программы не устаревали и нормально работали с неаппаратными звуковыми подсистемами и низкоуровневыдрайверами пространства пользователя, такими как Bluetooth- и FireWire-аудио. Некоторые из этих рекомендаций применимы также и для полного API ALSA, но часть функциональности можно считать устаревшей в любом случае.

У вас должна быть серьезная причина, чтобы писать код, не соответствующий этим правилам. Иначе этот код можно будет просто считатьнеработоспособным!

Что НЕ НАДО делать:

  • Не используйте “обработчики async”, например snd_async_add_pcm_handler() и тому подобные. Асинхронные обработчики реализованы с применением сигналов POSIX, а это весьма спорное их применение, особенно для библиотек и подключаемых модулей. Даже если нежелательно ограничиваться безопасной частью ALSA, лучше не использовать такие функции. Здесь подробно описывается, почему не стоит использовать сигналы для ввода-вывода звука.
  • Не берите данные из конфигурационного файла ALSA самостоятельно или с помощью любой из функций ALSA, подобныхsnd_config_xxx(). Если нужно пронумеровать аудиоустройства, используйте snd_device_name_hint() (и связанные с ней функции). Только в этом API есть также поддержка нумерации виртуальных аудиоустройств и аудиоустройств с драйверами в пространстве пользователя.
  • Не берите данные из файлов, расположенных в /proc/asound/. В этих файлах содержится информация только о звуковых драйверах ядра, подключаемых модулей пространства пользователя там нет. Кроме того, устройства в ядре могут отличаться от их представления в пространстве пользователя (то есть подчиненные устройства могут обозначаться не так, как устройства пространства пользователя, например surround51 и аналогичные).
  • Не рассчитывайте на стабильность списков устройств в ALSA. На данный момент они зависят от порядка инициализации драйверов во время загрузки и поэтому могут изменяться.
  • Не используйте API snd_card_xxx(). Для нумерации используйте snd_device_name_hint() (и связанные с ней функции). Функцияsnd_card_xxx() устарела. Она просто перечисляет аппаратные устройства в ядре. Устройства пространства пользователя, такие как звуковые серверы и Bluetooth-аудио не поддерживаются. Функция snd_card_load() на данный момент полностью устарела.
  • Не задавайте жестко в коде строки устройств, особенно hw:0 или plughw:0, или даже dmix — эти устройства не определяют назначение каналов, они назначены на устройства ядра. Крайне желательно использовать для строк устройств только default. Если требуется особое переназначение каналов, правильной строкой устройств будет front для стерео, surround40 для четырехканального звука 4.0,surround41surround51 и так далее. К сожалению, на данный момент ALSA определяет стандартные наименования устройств с назначением каналов только для устройств ядра. Это означает, что default можно безопасно применять только для моно- и стереопотоков. Возможно, стоит начинать строки устройств с plug:, чтобы ALSA выполнялось переформатирование, переназначение или конвертация PCM-потока, если устройство или звуковая подсистема не поддерживает требуемые параметры дискретизации.
  • Не рассчитывайте, что поддерживается какой-либо тип дискретизации кроме U8, S16_LE, S16_BE, S32_LE, S32_BE, FLOAT_LE, FLOAT_BE, MU_LAW и A_LAW.
  • Не используйте для синхронизации snd_pcm_avail_update(). Эта функция должна использоваться только для запроса количества байт, которое можно считать или записать в данный момент. Не используйте snd_pcm_delay() для запроса уровня заполнения буфера воспроизведения. Эта функция должна использоваться только для синхронизации. Удостоверьтесь, что вы полностью понимаете различие. Помните, что эти две функции возвращают значения, которые не взаимосвязаны непосредственно!
  • Не рассчитывайте, что в органах управления микшером всегда будет информация об уровне в децибелах.
  • Не рассчитывайте, что все устройства поддерживают доступ к буферу в стиле MMAP.
  • Не рассчитывайте, что указатель оборудования в буфере воспроизведения (возможно, с применением mmap) отображает действительную позицию сэмпла в DAC. Могут возникать дополнительные задержки.
  • Не пытайтесь с помощью собственного кода проводить восстановление после сбоев ALSA, таких как опустошение буфера. Используйте вместо этого snd_pcm_recover().
  • Не трогайте метрики буферизации и периодов, если нет необходимости выставлять особые задержки. Будьте осторожны в разработке, аккуратно обрабатывая ситуации, в которых подсистема не может выполнить ваши запросы метрик буферизации. Помните, что во многих случаях размер буфера воспроизведения не оказывает непосредственного влияния на общее значение задержки. То есть установка фиксированного размера буфера может на практике привести к гораздо большим задержкам.
  • Не рассчитывайте, что функция snd_pcm_rewind() доступна и полностью работоспособна.
  • Не рассчитывайте, что время, когда PCM-поток может получать новые данные, строго зависит от параметров дискретизации и буферизации и от окончательной пропускной способности. Всегда проверяйте, чтобы новые аудиоданные поступали устройству, когда оно их запрашивает, сигнализируя о доступности для записи в fd (и аналогично для захвата).
  • Не используйте “простой” интерфейс snd_spcm_xxx().
  • Не используйте функций, помеченных как “устаревшие”.
  • Не используйте подсистемы timer, midi, rawmidi, hwdep.

Что НАДО делать:

  • Используйте snd_device_name_hint() для нумерации аудиоустройств.
  • Используйте snd_smixer_xx() вместо чистого snd_ctl_xxx().
  • Для синхронизации используйте snd_pcm_delay().
  • Для проверки уровня заполнения буфера воспроизведения/захвата используйте snd_pcm_update_avail().
  • Используйте snd_pcm_recover() для восстановления после ошибок, возвращаемых любыми функциями ALSA.
  • По возможности используйте наибольший поддерживаемый устройствами размер буфера, чтобы минимизировать энергопотребление и для защиты от выпадений звука. Используйте snd_pcm_rewind(), если нужна быстрая реакция на пользовательский ввод.

FAQ

А как насчет ESD и NAS?

ESD и NAS устарели, и как API, и как звуковой демон. Не применяйте их больше в разработке.

ALSA не портируется!

Это неверно! На самом деле библиотека пространства пользователя относительно портируема, в нее даже входит звуковая подсистема для аудиоустройств OSS. Нет реальных причин, мешающих использовать библиотеки ALSA на других Unix-подобных системах.

Для меня важнее всего переносимость! Что делать?

К сожалению, пока нет PCM API, действительно портируемого (то есть на Win32), который можно было бы посоветовать. Описанные выше системы более или менее портируемы, по крайней мере на Unix-подобные ОС. Но это не значит, что для них всех доступны подходящие подсистемы. Если для вас важна переносимость на Win32 и MacOS, возможно, стоит поискать решения, не перечисленные среди рекомендаций выше, либо помочь доработать переносимость необходимых подсистем. Ни одна из систем (за исключением OSS) не привязана жестко к ядру Linux или других Unix-подобных систем.

А как насчет PortAudio?

Не думаю, что PortAudio — хороший API для Unix-подобных операционных систем. Не могу его рекомендовать, но решайте сами.

А почему вы так ненавидите OSS4?

Я ничего не ненавижу. Просто не думаю, что OSS4 — серьезный выбор, особенно для Linux. Под Linux он абсолютно бесполезен, так как есть ALSA.

Вы идиот и ничего не смыслите!

Совершенно верно, не смыслю. Но это не мешает мне давать советы. Ха!

Я создал новый проектик, отлично реализующий уровень абстракций для аудио и мультимедиа!

Извините, но этого недостаточно. Я перечисляю здесь только программы, которые точно подходят и достаточно хорошо поддерживаются.

Заключение

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

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

Если вы считаете, что я забыл упомянуть какое-то практическое применение или важный API, напишите мне или оставьте комментарий. Однако полагаю, что выше все изложено достаточно исчерпывающе, и если что-то пропущено, то скорее всего умышленно.

Кроме того, учитывайте то, что я участвую в разработке PulseAudio и libcanberra, а также вношу небольшой вклад в ALSA, GStreamer и некоторые другие из перечисленных систем. Да, я пристрастен.

Да, и пожалуйста, размещайте ссылки на этот материал. Я хочу, чтобы это руководство было широко известно в Linux-сообществе. Спасибо!


Прим.: PCM расшифровывается как импульсно-кодовая модуляция (pulse code modulation) и обеспечивает цифровое представление аналогового сигнала, который дискретизируется (оцифровывается) через равные промежутки времени (с заданной в герцах частотой) и представляется в двоичном виде (с заданной точностью – разрядностью в битах).


Поделиться заметкой:
Узнать версию Linux
Все способы узнать версию дистрибутива Linux (а также FreeBSD, MacOS и прочих)
Права на файлы
Права на файлы и папки в Linux, FreeBSD и MacOS
Настоящий интеллект
  • Юрий

    Доброго времени суток! Я 2 дня как установил linux Mint 17. В радости, что всё получилось, не обратил внимания на то, что звук ( у меня свен 2+1 ) не полный, то есть левый канал и сабвуфер работают, а правый отдыхает… Мои познания в линуксе равны нолю, по этому обращаюсь к спецам с надеждой, что поможете. Заранее благодарю.