访问音频系统资源

Java Sound API 采用了灵活的系统配置方法。可以在计算机上安装不同种类的音频设备(调音台)。该 API 对已安装的设备及其功能没有多少假设。相反,它提供了系统报告可用音频组件的方式以及程序访问它们的方式。

以下各节说明程序如何了解计算机上已安装了哪些采样音频资源,以及如何获取对可用资源的访问权限。其中,资源包括混合器和混合器拥有的各种类型的线路。

AudioSystem 类

AudioSystem类充当音频组件的交换所,包括内置服务和第三方提供商单独安装的服务。 AudioSystem用作访问这些已安装的采样音频资源的应用程序的入口点。您可以查询AudioSystem以了解已安装了哪些资源,然后可以访问它们。例如,应用程序可能会通过询问AudioSystem类是否存在具有特定配置的混合器来开始,例如在前面的讨论中已说明的 Importing 或输出配置之一。然后,程序将从混合器中获取数据线,依此类推。

以下是应用程序可以从AudioSystem获得的一些资源:

  • 混合器—系统通常安装了多个混合器。通常至少有一个用于音频 Importing,一个至少用于音频输出。可能还有一些混音器没有 I/O 端口,而是接受来自应用程序的音频,然后将混合的音频传递回该程序。 AudioSystem类提供了所有已安装的调音台的列表。

  • 行-即使每行都与一个混频器相关联,应用程序也可以直接从AudioSystem获得一条线,而无需显式处理混频器。

  • 格式转换-应用程序可以使用格式转换将音频数据从一种格式转换为另一种格式。

  • 文件和流— AudioSystem类提供了在音频文件和音频流之间进行转换的方法。它还可以报告声音文件的文件格式,并可以以不同的格式写入文件。

Information Objects

Java Sound API 中的几个类提供有关关联interface的有用信息。例如,Mixer.Info提供有关已安装的混音器的详细信息,例如混音器的供应商,名称,描述和版本。 Line.Info获取特定行的类。 Line.Info的子类包括Port.InfoDataLine.Info,它们分别获取与特定端口和数据线有关的详细信息。这些类别中的每一个将在下面的相应部分中进行进一步说明。重要的是不要将Info对象与其描述的混合器或线路对象混淆。

获取调音台

通常,使用 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对象中的信息不会有太大用处。相反,您可以遍历getMixerInfo返回的所有Mixer.Info对象,通过调用getMixer获得每个对象的混合器,并查询每个混合器的功能。例如,您可能需要一个混音器,可以同时将其混合音频数据写入一定数量的目标数据线。在这种情况下,您可以使用Mixer方法查询每个混音器:

int getMaxLines(Line.Info info)

在这里Line.Info将指定TargetDataLine。下一部分将讨论Line.Info类。

获取所需类型的线

有两种方法可以获得一条线:

  • 直接来自AudioSystem对象

  • 从您已经从AudioSystem对象获得的混合器中

直接从音频系统获取线路

假设您尚未获得混合器,并且您的程序是一个简单的程序,实际上只需要某种类型的行;调音台的详细信息对您而言并不重要。您可以使用AudioSystem方法:

static Line getLine(Line.Info info)

与之前讨论的getMixer方法类似。与Mixer.Info不同,用作参数的Line.Info不会存储文本信息来指定所需的行。相反,它存储有关所需线路类别的信息。

Line.Info是抽象类,因此您可以使用其子类之一(Port.InfoDataLine.Info)获得一行。以下代码摘录使用DataLine.Info子类来获取并打开目标数据行:

TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
    format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) {
    // Handle the error.
    }
    // Obtain and open the line.
try {
    line = (TargetDataLine) AudioSystem.getLine(info);
    line.open(format);
} catch (LineUnavailableException ex) {
        // Handle the error.
    //... 
}

此代码获取TargetDataLine对象,但未指定其类和音频格式以外的任何属性。您可以使用类似的代码来获取其他类型的行。对于SourceDataLineClip,只需将TargetDataLine的类替换为 line 变量的类,并在DataLine.Info构造函数的第一个参数中。

对于Port,您可以使用Port.Info的静态实例,其代码如下所示:

if (AudioSystem.isLineSupported(Port.Info.MICROPHONE)) {
    try {
        line = (Port) AudioSystem.getLine(
            Port.Info.MICROPHONE);
    }
}

请注意使用方法isLineSupported来查看混音器是否还具有所需类型的行。

回想一下,源线是混音器的 Importing,如果混音器表示音频 Importing 设备,则为Port对象,如果混音器表示音频输出设备,则为SourceDataLineClip对象。类似地,目标行是混合器的输出:用于音频输出混合器的Port对象,以及用于音频 Importing 混合器的TargetDataLine对象。如果调音台根本不连接任何外部硬件设备怎么办?例如,考虑一个内部或纯软件混音器,它从应用程序中获取音频并将其混合后的音频传递回该程序。这种混合器的 Importing 线具有SourceDataLineClip对象,而输出线具有TargetDataLine对象。

您还可以使用以下AudioSystem方法来了解有关已安装的混音器支持的指定类型的源行和目标行的更多信息:

static Line.Info[] getSourceLineInfo(Line.Info info)
static Line.Info[] getTargetLineInfo(Line.Info info)

请注意,这些方法中的每一个返回的数组都表示行的唯一类型,不一定是所有行。例如,如果混音器的两行或不同混音器的两行具有相同的Line.Info对象,则在返回的数组中,这两行将仅由一个Line.Info表示。

从调音台获得线路

Mixerinterface包括上述针对源线和目标线的AudioSystem访问方法的变体。这些Mixer方法包括采用Line.Info参数的方法,就像AudioSystem's方法一样。但是,Mixer还包括以下变体,它们不带任何参数:

Line.Info[] getSourceLineInfo()
Line.Info[] getTargetLineInfo()

这些方法返回特定混音器的所有Line.Info对象的数组。一旦获得数组,就可以遍历它们,调用Mixer's getLine方法获取每一行,然后调用Line's open方法为程序保留每一行的使用。

选择 Importing 和输出端口

关于如何获取所需类型的线的上一节,适用于端口以及其他类型的线。您可以通过将Port.Info对象传递给采用Line.Info参数的getSourceLineInfogetTargetLineInfo方法getSourceLineInfogetTargetLineInfo来获取所有源(即 Importing)和目标(即输出)端口。然后,您遍历返回的对象数组,并调用 Mixer 的getLine方法以获取每个端口。

然后可以通过调用Line's open方法来打开每个Port。打开端口意味着您将其打开-也就是说,您允许声音进入或流出端口。同样,您可以关闭不希望声音传播的端口,因为某些端口可能在您获得它们之前就已经打开。某些平台默认情况下将所有端口保留为打开状态。或者用户或系统 管理 员可能已使用其他应用程序或 os 软件选择了要打开或关闭的某些端口。

警告: 如果要选择某个端口并确保声音实际上是在端口中进出,则可以按照说明打开端口。但是,这可以视为对用户有害的行为!例如,用户可能会关闭扬声器端口,以免打扰她的同事。如果您的程序突然破坏了她的愿望并开始大肆歌唱,她会很不高兴。作为另一个示例,用户可能希望确保自己的计算机的麦克风永远不会在不知情的情况下打开,以避免窃听。通常,建议不要打开或关闭端口,除非您的程序响应用户的意图(通过用户interface表示)。相反,请遵守用户或 os 已选择的设置。

无需先打开或关闭端口,连接的调音台才能正常运行。例如,即使关闭了所有输出端口,也可以开始将声音回放到音频输出混音器中。数据仍然流入混合器;播放不会被阻止。用户只是什么也听不到。用户一旦打开输出端口,便会从该端口上的声音开始听到声音,该声音将从已播放的媒体中的任何一点开始。

另外,您无需访问端口即可了解混音器是否具有某些端口。例如,要了解混音器是否实际上是音频输出混音器,可以调用getTargetLineInfo来查看它是否具有输出端口。除非您要更改端口设置(例如,端口的打开或关闭状态或它们可能具有的任何控件的设置),否则没有理由访问端口本身。

允许使用音频资源

Java Sound API 包括AudioPermission类,该类指示 Servlets(或运行有安全 管理 器的应用程序)可以对采样音频系统进行哪种访问。录制声音的权限是单独控制的。应当谨慎授予此权限,以帮助防止诸如未经授权的窃听之类的安全风险。默认情况下,Servlets 和应用程序被授予以下权限:

  • 与 applet 安全 管理 器一起运行的* applet *可以播放但不能录制音频。

  • 没有安全 管理 器运行的应用程序可以播放和录制音频。

  • 使用默认安全 管理 器运行的应用程序可以播放但不能录制音频。

通常,Servlets 在安全 管理 器的监督下运行,并且不允许录制声音。另一方面,应用程序不会自动安装安全 管理 器,并且能够录制声音。 (但是,如果为应用程序显式调用了默认安全 管理 器,则不允许该应用程序记录声音.)

Servlets 和应用程序都可以录制声音,即使它们已被授予显式权限,即使在使用安全 管理 器运行时也可以录制声音。

如果您的程序无权录制(或播放)声音,则在try打开一行时会引发异常。除了catch异常并将问题报告给用户外,您在程序中无能为力,因为无法通过 API 更改权限。 (如果可以,它们将毫无意义,因为没有什么安全的!)通常,权限是在一个或多个策略配置文件中设置的,用户或系统 管理 员可以使用文本编辑器或“策略工具”程序对其进行编辑。