Заметка

В версии 5.0 новые конструкторы для AudioFormat, AudioFileFormat, и MidiFileFormat позволяют описывать более сложные форматы.

 

Что такое сервисы?

Сервисы - это единицы функциональности обработки звука, которые автоматически становятся доступными, когда прикладная программа использует реализацию Java Sound API. Они состоят из объектов, которые выполняют работу по чтению, записи, микшированию, обработке и преобразованию аудио- и MIDI-данных. Реализация Java Sound API обычно предоставляет базовый набор услуг, но в API также включены механизмы для поддержки разработки новых звуковых сервисов сторонними разработчиками (или поставщиком самой реализации). Эти новые службы могут быть «подключены» к существующей установленной реализации, чтобы расширить ее функциональные возможности, не требуя нового выпуска. В архитектуре Java Sound API сторонние сервисы интегрированы в систему таким образом, что интерфейс прикладной программы для них такой же, как интерфейс для «встроенных» сервисов. В некоторых случаях разработчики приложений, использующие пакеты javax.sound.sampled и javax.sound.midi, могут даже не знать, что они используют сторонние службы.

Примеры потенциальных сторонних сервисов сэмплированного аудио включают:

  • Читатели и писатели звуковых файлов
  • Конвертеры, которые переводят между различными форматами аудиоданных
  • Новые аудиомикшеры и устройства ввода / вывода, реализованные чисто программно или аппаратно с программным интерфейсом

Сторонние MIDI-сервисы могут включать:

  • Читатели и писатели MIDI файлов
  • Читатели для различных типов файлов звукового банка (которые часто специфичны для конкретных синтезаторов)
  • Управляемые по MIDI звуковые синтезаторы, секвенсоры и порты ввода-вывода, реализованные исключительно программно или аппаратно с программным интерфейсом

Как работают сервисы.

Пакеты javax.sound.sampled и javax.sound.midi предоставляют функциональные возможности разработчикам приложений, которые хотят включить звуковые службы в свои прикладные программы. Эти пакеты предназначены для потребителей звуковых служб и предоставляют интерфейсы для получения информации, управления и доступа к аудио- и MIDI-службам. Кроме того, Java Sound API также предоставляет два пакета, которые определяют абстрактные классы, которые будут использоваться поставщиками звуковых служб: пакеты javax.sound.sampled.spi и javax.sound.midi.spi.

Разработчики новых звуковых сервисов реализуют конкретные подклассы соответствующих классов в пакетах SPI. Эти подклассы вместе с любыми дополнительными классами, необходимыми для поддержки новой службы, помещаются в архивный файл Java Archive (JAR) с описанием включенной службы или служб. Когда этот JAR-файл устанавливается в пользовательский CLASSPATH, исполняющая система автоматически делает новую службу доступной, расширяя функциональные возможности исполняющей системы платформы Java.

После установки новой службы к ней можно будет получить доступ, как к любой ранее установленной службе. Потребители служб могут получить информацию о новой службе или экземпляры самого нового класса службы, вызвав методы классов AudioSystem и MidiSystem (в пакетах javax.sound.sampled и javax.sound.midi соответственно) для возврата информацию о новых сервисах или возвращать экземпляры новых или существующих классов сервиса. Прикладным программам не нужно - и не следует - ссылаться на классы в пакетах SPI (и их подклассах) напрямую, чтобы использовать установленные службы.

Например, предположим, что гипотетический поставщик услуг под названием Acme Software, Inc. заинтересован в предоставлении пакета, который позволяет прикладным программам читать звуковой файл нового формата (но тот, аудиоданные которого находятся в стандартном формате данных). SPI-класс AudioFileReader может быть разделен на подкласс, например, AcmeAudioFileReader. В новом подклассе Acme предоставит реализации всех методов, определенных в AudioFileReader; в этом случае есть только два метода (с вариантами аргументов): getAudioFileFormat и getAudioInputStream. Затем, когда прикладная программа пыталась прочитать звуковой файл, который оказался в файловом формате Acme, она вызывала методы класса AudioSystem в javax.sound.sampled для доступа к файлу и информации о нем. Методы AudioSystem.getAudioInputStream и AudioSystem.getAudioFileFormat предоставляют стандартный API для чтения аудиопотоков; с установленным классом AcmeAudioFileReader этот интерфейс расширяется для прозрачной поддержки нового типа файла. Разработчикам приложений не нужен прямой доступ к недавно зарегистрированным классам SPI: методы объекта AudioSystem передают запрос установленному классу AcmeAudioFileReader.

Какой смысл иметь эти "фабричные" классы? Почему бы не разрешить разработчику приложения получить доступ непосредственно к вновь предоставляемым услугам? Это возможный подход, но когда все управление и создание экземпляров служб проходят через системные объекты gatekeeper, разработчик приложения не должен ничего знать об идентичности установленных служб. Разработчики приложений просто пользуются ценными для них услугами, возможно, даже не осознавая этого. В то же время эта архитектура позволяет поставщикам услуг эффективно управлять доступными ресурсами в своих пакетах.

Часто использование новых звуковых сервисов прозрачно для прикладной программы. Например, представьте себе ситуацию, когда разработчик приложения хочет прочитать в потоке аудио из файла. Предполагая, что thePathName идентифицирует входной аудиофайл, программа делает это:

    File theInFile = new File(thePathName);
    AudioInputStream theInStream = AudioSystem.getAudioInputStream(theInFile);

За кулисами AudioSystem определяет, какая установленная служба может читать файл, и просит его предоставить аудиоданные в виде объекта AudioInputStream. Разработчик может не знать или даже не заботиться о том, что входной аудиофайл находится в каком-то новом формате файла (например, Acme), поддерживаемом установленными сторонними службами. Первый контакт программы с потоком осуществляется через объект AudioSystem, а весь последующий доступ к потоку и его свойствам осуществляется через методы AudioInputStream. Оба они являются стандартными объектами в API javax.sound.sampled; особая обработка, которую может потребовать новый формат файла, полностью скрыта.

Как провайдеры готовят новые службы.

Поставщики услуг предоставляют свои новые услуги в виде специально отформатированных файлов JAR, которые должны быть установлены в каталог в системе пользователя, где их найдет среда выполнения Java. Файлы JAR - это архивные файлы, каждый из которых содержит наборы файлов, которые могут быть организованы в иерархические структуры каталогов внутри архива. Подробности о подготовке файлов классов, которые попадают в эти архивы, обсуждаются в главах 14 и 15, в которых описываются особенности пакетов аудио и MIDI SPI; здесь мы просто дадим обзор процесса создания файла JAR.

Файл JAR для новой службы или служб должен содержать файл класса для каждой службы, поддерживаемой в файле JAR. Следуя соглашению платформы Java, каждый файл класса имеет имя нового определенного класса, который является конкретным подклассом одного из абстрактных классов поставщика услуг. Файл JAR также должен включать все вспомогательные классы, необходимые для реализации новой службы. Чтобы новая услуга или услуги могли быть обнаружены механизмом поставщика услуг исполняющей системы, файл JAR также должен содержать специальные файлы (описанные ниже), которые сопоставляют имена классов SPI с новыми определяемыми подклассами.

Продолжая наш пример выше, предположим, что Acme Software, Inc. распространяет пакет новых сервисов сэмплированного аудио. Предположим, этот пакет состоит из двух новых сервисов:

  • Упомянутый выше класс AcmeAudioFileReader, который является подклассом AudioFileReader.
  • Подкласс AudioFileWriter под названием AcmeAudioFileWriter, который будет записывать звуковые файлы в новом формате Acme.

Начиная с произвольного каталога - назовем его /devel - в котором мы хотим выполнить сборку, мы создаем подкаталоги и помещаем в них новые файлы классов, организованные таким образом, чтобы дать желаемое имя пути, по которому будут размещаться новые классы. упоминается:

    com/acme/AcmeAudioFileReader.class
    com/acme/AcmeAudioFileWriter.class

Кроме того, для каждого нового подкласса SPI мы создаем файл сопоставления в каталоге со специальным именем META-INF/services. Имя файла - это имя подкласса SPI-класса, а файл содержит имена новых подклассов этого абстрактного SPI-класса.

Создаем файл

META-INF/services/javax.sound.sampled.spi.AudioFileReader, который состоит из

    # Providers of sound file-reading services 
    # (a comment line begins with a pound sign)
    com.acme.AcmeAudioFileReader

а также файл

META-INF/services/javax.sound.sampled.spi.AudioFileWriter, который состоит из

   # Providers of sound file-writing services 
    com.acme.AcmeAudioFileWriter

Теперь запускаем jar из любого каталога с помощью командной строки:

jar cvf acme.jar -C /devel .

Параметр -C заставляет jar переключаться в каталог /devel вместо использования каталога, в котором выполняется команда. Последний аргумент периода указывает jar архивировать все содержимое этого каталога (а именно /devel), но не сам каталог.

Этот запуск создаст файл acme.jar с содержимым:

com/acme/AcmeAudioFileReader.class
com/acme/AcmeAudioFileWriter.class
META-INF/services/javax.sound.sampled.spi.AudioFileReader
META-INF/services/javax.sound.sampled.spi.AudioFileWriter
META-INF/Manifest.mf

Файл Manifest.mf, который создается самой утилитой jar, представляет собой список всех файлов, содержащихся в архиве.

Как пользователи устанавливают новые службы.

Для конечных пользователей (или системных администраторов), которые хотят получить доступ к новой службе через свои прикладные программы, установка проста. Они помещают предоставленный JAR-файл в каталог своего CLASSPATH. После выполнения среда выполнения Java при необходимости найдет классы, на которые имеются ссылки.

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

 

Предыдущая Следующая