Глава 03: Доступ к ресурсам аудиосистемы
Заметки
|
Java Sound API использует гибкий подход к настройке системы. На компьютер могут быть установлены различные типы аудиоустройств (микшеров). API делает несколько предположений о том, какие устройства были установлены и каковы их возможности. Вместо этого он предоставляет системе способы сообщения о доступных аудиокомпонентах и способы доступа к ним для вашей программы.
В этом разделе показано, как ваша программа может узнать, какие ресурсы дискретизированного звука были установлены на компьютере, и как она может получить доступ к доступным ресурсам. Среди прочего, ресурсы включают микшеры и различные типы линий, принадлежащие микшерам.
Класс AudioSystem
Класс AudioSystem действует как информационная служба для аудиокомпонентов, включая встроенные службы и отдельно установленные службы от сторонних поставщиков. AudioSystem служит точкой входа прикладной программы для доступа к этим установленным ресурсам дискретизированного звука. Вы можете запросить AudioSystem, чтобы узнать, какие виды ресурсов были установлены, а затем вы можете получить к ним доступ. Например, прикладная программа может начинаться с запроса класса AudioSystem, существует ли микшер с определенной конфигурацией, такой как одна из конфигураций ввода или вывода, показанных ранее при обсуждении линий. Затем из микшера программа получит линии данных и так далее.
Вот некоторые из ресурсов, которые прикладная программа может получить от AudioSystem:
- Mixers В системе обычно установлено несколько микшеров. Обычно есть как минимум один для аудиовхода и один для аудиовыхода. Также могут быть микшеры, у которых нет портов ввода-вывода, но вместо этого они принимают звук из прикладной программы и доставляют смешанный звук обратно в программу. Класс AudioSystem предоставляет список всех установленных микшеров.
- Lines Несмотря на то, что каждая линия связана с микшером, прикладная программа может получить линию непосредственно из AudioSystem, не обращаясь явно к микшерам.
- Преобразование форматов Прикладная программа может использовать преобразование формата для перевода аудиоданных из одного формата в другой. Преобразования описаны в главе 7 "Использование файлов и конвертеров формата."
- Файлы и потоки Класс AudioSystem предоставляет методы для перевода между аудиофайлами и аудиопотоками. Он также может сообщать формат файла звукового файла и может записывать файлы в разных форматах. Эти возможности обсуждаются в главе 7 "Использование файлов и конвертеров формата."
Информационные объекты
Несколько классов в Java Sound API предоставляют полезную информацию о связанных интерфейсах. Например, Mixer.Info предоставляет подробную информацию об установленном микшере, такую как поставщик микшера, имя, описание и версия. Подклассы Line.Info получает класс конкретной линии. Подклассы Line.Info включают Port.Info и DataLine.Info, которые получают сведения, относящиеся к определенному порту и линии данных, соответственно. Каждый из этих классов подробно описан в соответствующем разделе ниже. Важно не путать объект Info с объектом mixer или line, который он описывает.
Получение микшера
Обычно одна из первых вещей, которые необходимо сделать программе, использующей Java Sound API, - это получить микшер или хотя бы одну линию микшера, чтобы вы могли передавать звук в компьютер или из него. Вашей программе может потребоваться микшер определенного типа, или вы можете отобразить список всех доступных микшеров, чтобы пользователь мог выбрать один. В любом случае вам необходимо узнать, какие типы микшеров установлены. AudioSystem предоставляет следующий метод:
static Mixer.Info[] getMixerInfo()
Каждый объект Mixer.Info, возвращаемый этим методом, идентифицирует один тип установленного микшера. (Обычно в системе есть не более одного микшера данного типа. Если их несколько, возвращаемый массив по-прежнему имеет только один Mixer.Info для этого типа.) Прикладная программа может выполнять итерацию по Mixer.Info, чтобы найти подходящий объект в соответствии с его потребностями. Mixer.Info включает следующие строки для определения типа микшера:
- Name - имя
- Version - Версия
- Vendor - поставщик
- Description - Описание
Это произвольные строки, поэтому прикладная программа, которой нужен конкретный микшер, должна знать, чего ожидать и с чем их сравнивать. Поставщик, предоставляющий микшер, должен включить эту информацию в свою документацию. В качестве альтернативы, и, возможно, более типично, прикладная программа будет отображать все строки объектов Mixer.Info пользователю и пусть пользователь выбирает соответствующий микшер.
Как только подходящий микшер найден, прикладная программа вызывает следующий метод AudioSystem для получения желаемого микшера:
static Mixer getMixer(Mixer.Info info)
Что делать, если вашей программе нужен микшер с определенными возможностями, но не нужен конкретный микшер от конкретного производителя? А что, если нельзя полагаться на то, что пользователь знает, какой микшер выбрать? В этом случае информация в объектах Mixer.Info будет бесполезна. Вместо этого вы можете перебирать все объекты Mixer.Info, возвращаемые getMixerInfo, получать микшер для каждого, вызывая getMixer, и запрашивать у каждого микшера его возможности. Например, вам может потребоваться микшер, который может записывать свои смешанные аудиоданные в определенное количество целевых линий данных одновременно. В этом случае вы должны запросить каждый микшер, используя этот метод Mixer: int getMaxLines(Line.Info info)
Здесь Line.Info указывает TargetDataLine. Класс Line.Info обсуждается в следующем разделе.
Получение линии желаемого типа
Есть два способа получить линию:
- Непосредственно из объекта AudioSystem
- Из микшера, который вы уже получили из объекта AudioSystem (см. "Получение микшера," в этой главе)
Получение линии напрямую из AudioSystem
Предположим, у вас нет микшера, а ваша программа проста, и ей действительно нужны только определенные линии; детали микшера для вас не важны. Вы можете использовать метод AudioSystem:
static Mixer getMixer(Line.Info info)
который аналогичен описанному выше методу getMixer. В отличие от Mixer.Info, Line.Info, используемый в качестве аргумента, не хранит текстовую информацию для указания нужной линии. Вместо этого он хранит информацию о желаемом классе линии.
Line.Info - это абстрактный класс, поэтому вы используете один из его подклассов (Port.Info или DataLine.Info) для получения линии. В следующем фрагменте кода используется подкласс DataLine.Info для получения и открытия целевой линии данных:
TargetDataLine line; DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format - это объект AudioFormat if (!AudioSystem.isLineSupported(info)) { // Обработать ошибку. } // Получить и открыть линию. try { line = (TargetDataLine) AudioSystem.getLine(info); line.open(format); } catch (LineUnavailableException ex) { // Обработать ошибку. //... }
Этот код получает объект TargetDataLine без указания каких-либо атрибутов, кроме его класса и его аудиоформата. Вы можете использовать аналогичный код для получения других типов линий. Для SourceDataLine или Clip просто замените этот класс TargetDataLine в качестве класса переменной line, а также в первом аргументе конструктора DataLine.Info.
Для Port вы можете использовать статические экземпляры Port.Info в следующем коде:
if (AudioSystem.isLineSupported(Port.Info.MICROPHONE)) { try { line = (Port) AudioSystem.getLine( Port.Info.MICROPHONE); } }
Обратите внимание на использование метода isLineSupported, чтобы увидеть, есть ли в микшере даже линия желаемого типа.
Напомним, что входящая линия является входом для микшера, а именно, объект Port, если микшер представляет устройство ввода звука, и объект SourceDataLine или Clip, если микшер представляет устройство вывода звука. Точно так же целевая линия является выходом микшера: объект Port для микшера аудиовыхода и объект TargetDataLine для микшера аудиовхода. Что делать, если микшер вообще не подключается ни к какому внешнему устройству? Например, рассмотрим внутренний или программный микшер, который получает звук из прикладной программы и доставляет его обратно в программу. Этот вид микшера имеет объекты SourceDataLine или Clip для входных линий и объекты TargetDataLine для своих линий вывода.
Вы также можете использовать следующие методы AudioSystem, чтобы узнать больше об исходных и целевых линиях указанного типа, которые поддерживаются любым установленным микшером:
static Line.Info[] getSourceLineInfo(Line.Info info) static Line.Info[] getTargetLineInfo(Line.Info info)
Обратите внимание, что массив, возвращаемый каждым из этих методов, указывает уникальные типы линий, не обязательно все линии. Например, если две линии микшера или две линии разных микшеров имеют одинаковые объекты Line.Info, эти две линии будут представлены только одним Line.Info в возвращаемом массиве.
Получение линии из микшера
Интерфейс Mixer включает варианты методов доступа к AudioSystem для исходных и целевых линий, описанных выше. Эти методы Mixer включают те, которые принимают аргументы Line.Info, как и методы AudioSystem's. Однако Mixer также включает варианты, которые не принимают аргументов:
Line.Info[] getSourceLineInfo() Line.Info[] getTargetLineInfo()
Эти методы возвращают массивы всех объектов Line.Info для конкретного микшера. После того, как вы получили массивы, вы можете перебирать их, вызывая метод getLine класса Mixer для получения каждой линии, а затем метод open класса Line , чтобы зарезервировать использование каждой линии для вашей программы.
Выбор портов ввода и вывода
Предыдущий раздел о том, как получить линию желаемого типа, применяется как к портам, так и к другим типам линий. Вы можете получить все исходные (т. е. input) и целевые (т. е. output) порты, передав объект Port.Info в методы getSourceLineInfo и getTargetLineInfo класса AudioSystem (или Mixer) , которые принимают аргумент Line.Info Затем вы перебираете возвращенный массив объектов и вызываете метод Mixer getLine для получения каждого порта.
Затем вы можете открыть каждый Port, вызвав метод open класса Line. Открытие порта означает, что вы включаете его, то есть позволяете звуку входить или выходить из порта. Точно так же вы можете закрыть порты, через которые не хотите проходить звук, потому что некоторые порты могут быть открыты еще до того, как вы их получите. Некоторые платформы оставляют все порты включенными по умолчанию; либо пользователь или системный администратор мог включить или выключить определенные порты с помощью другой прикладной программы или программного обеспечения операционной системы.
Предупреждение: Если вы хотите выбрать определенный порт и убедиться, что звук действительно входит или выходит из порта, вы можете открыть порт, как описано. Однако это можно считать враждебным по отношению к пользователю поведением! Например, у пользователя может быть отключен порт динамика, чтобы не беспокоить своих коллег. Она будет очень расстроена, если ваша программа вдруг превзойдет ее пожелания и начнет гудеть музыкой. В качестве другого примера пользователь может захотеть быть уверенным, что микрофон его компьютера никогда не включается без его ведома, чтобы избежать подслушивания. В общем, рекомендуется не открывать или закрывать порты, если ваша программа не отвечает намерениям пользователя, выраженным через пользовательский интерфейс. Вместо этого соблюдайте настройки, которые уже были выбраны пользователем или операционной системой.
Нет необходимости открывать или закрывать порт, прежде чем микшер, к которому он подключен, будет работать правильно. Например, вы можете начать воспроизведение звука в микшере вывода звука, даже если все его порты вывода закрыты. Данные по-прежнему поступают в микшер; воспроизведение не заблокировано. Пользователь просто ничего не услышит. Как только пользователь откроет выходной порт, звук будет слышен через этот порт, начиная с любой точки носителя, которую уже достигло воспроизведение.
Кроме того, вам не нужно обращаться к портам, чтобы узнать, есть ли у микшера определенные порты. Чтобы узнать, действительно ли микшер является микшером вывода звука, например, вы можете вызвать getTargetLineInfo, чтобы узнать, есть ли у него порты вывода. Нет причин для доступа к самим портам, если вы не хотите изменить их настройки (например, их открытое или закрытое состояние или настройки любых элементов управления, которые они могут иметь).
Разрешение на использование аудиоресурсов
Java Sound API включает в себя класс AudioPermission, который указывает, какие виды доступа апплет (или приложение, работающее с менеджером безопасности) может иметь к системе сэмплированного звука. Разрешение на запись звука контролируется отдельно. Это разрешение следует предоставлять с осторожностью, чтобы предотвратить риски безопасности, такие как несанкционированное прослушивание. По умолчанию апплетам и приложениям предоставляются следующие разрешения:
- Апплет, работающий с менеджером безопасности апплетов, может воспроизводить, но не записывать звук.
- Приложение, работающее без диспетчера безопасности, может воспроизводить и записывать аудио.
- Приложение, работающее с менеджером безопасности по умолчанию, может воспроизводить, но не записывать аудио.
Как правило, апплеты запускаются под контролем менеджера по безопасности, и им не разрешается записывать звук. С другой стороны, приложения не устанавливают диспетчер безопасности автоматически и могут записывать звук. (Однако, если диспетчер безопасности по умолчанию вызывается для приложения явно, приложению не разрешается записывать звук.)
И апплеты, и приложения могут записывать звук даже при работе с менеджером безопасности, если им было предоставлено явное разрешение на это.
Если ваша программа не имеет разрешения на запись (или воспроизведение) звука, при попытке открыть линию будет выдано исключение. В вашей программе вы ничего не можете сделать с этим, кроме как перехватить исключение и сообщить о проблеме пользователю, потому что разрешения не могут быть изменены через API. (Если бы они могли, это было бы бессмысленно, потому что ничто не могло бы быть безопасным!) Обычно разрешения устанавливаются в одном или нескольких файлах конфигурации политики, которые пользователь или системный администратор может редактировать с помощью текстового редактора или программы Policy Tool.
Дополнительные сведения о безопасности и разрешениях см. В разделах «Архитектура безопасности» и «Разрешения политики» в руководстве по безопасности в руководстве по Java.
Предыдущая | Следующая |