【Java Sound】(二)访问音频系统资源

Java Sound

摘自:The Java™ Tutorials,翻译为机翻+少量修正

(二)访问音频系统资源

Java Sound API采用了灵活的系统配置方法。可以在计算机上安装不同种类的音频设备(mixers)。该API没怎么设想(makes few assumptions?)有什么已安装的设备以及其有什么功能。相反,它提供了让系统报告可用音频组件的方法以及让程序访问它们的方法。

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

AudioSystem类

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

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

  • Mixers,混音器——系统通常安装了多个混音器。通常至少有一个用于音频输入,一个用于音频输出。可能还有一些混音器没有I / O端口,而是接受来自应用程序的音频,并将混合的音频传递回该程序。本AudioSystem类提供所有已安装的混音器的列表。
  • Lines,线路——即使每条线路都与一个混合器相关联,应用程序也可以直接从AudioSystem中获得一条线路,而无需明确地和混音器打交道。
  • Format conversions,格式转换——应用程序可以使用格式转换将音频数据从一种格式转换为另一种格式。
  • Files and streams,文件和流——AudioSystem类提供在音频文件和音频流之间进行转换的方法。它还可以报告声音文件的文件格式,并可以以不同的格式写入文件。

Information Objects,信息对象

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

Getting a Mixer,获取一个混音器

通常,使用Java Sound API的程序需要做的第一件事是获取一个混音器,或者至少是一个混音器的一条线路,以便您可以将声音传入或传出计算机。您的程序可能需要一个特定类型的混音器,或者您可能希望显示所有可用混音器的列表,以便用户可以选择一个。无论哪种情况,您都需要了解安装了哪些类型的混音器。AudioSystem提供以下方法:

static Mixer.Info[] getMixerInfo()

此方法返回的每个Mixer.Info对象都标识一种已安装的混音器。(通常,系统最多只有一个给定类型的混合器。如果碰巧有不止一种给定类型的混合器,则返回的数组仍然只有Mixer.Info该类型的一个。)应用程序可以遍历Mixer.Info对象,根据需要来找到一个合适的混音器。Mixer.Info包括以下字符串,以确定一种混音器:

  • Name,名称
  • Version,版本
  • Vendor,供应商
  • Description,描述

这些是可以随意设定内容的字符串,因此需要特定混合器的应用程序必须知道期望的内容,和要去比对内容的字符串(难翻译, 给原文:what to expect and what to compare the strings to.)。提供混音器的公司应在其文档中包含此信息。替代地,并且可能更典型的情况是,应用程序将向用户显示所有Mixer.Info对象的字符串,并让用户选择相应的混合器。

找到合适的混合器后,应用程序将调用以下AudioSystem的方法以获得所需的混音器Mixer:

static Mixer getMixer(Mixer.Info info)

如果您的程序需要具有某些功能的混音器,而不需要特定供应商生产的特定混音器,该怎么办?而且,如果您不认为用户知道应该选择哪种混音器的时候呢?在这种情况下,Mixer.Info对象中的信息将没有太大用处。相反,您可以遍历getMixerInfo返回的所有Mixer.Info对象,通过调用getMixer为每个Info对象获取一个混合器,并向每个混合器查询其功能。例如,您可能需要一个混音器,它可以将其混合音频数据同时写入到一定数量的目标数据线。在这种情况下,您将使用此Mixer的方法查询每个混音器:

int getMaxLines(Line.Info info)

在这里, Line.Info将指定一个TargetDataLine。的Line.Info类将在下节讨论。

获取所需类型的线路line

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

  • 直接从 AudioSystem对象中获得
  • 从您已经从AudioSystem对象获得的混合器中获得
直接从AudioSystem获得线路

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

static Line getLine(Line.Info info)

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

Line.Info是一个抽象类,因此您可以使用其子类之一( Port.InfoDataLine.Info)获取一条线路line。以下的节选代码使用DataLine.Info子类获取并打开目标数据线路:

TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
    format); // format是一个AudioFormat类型的对象
if (!AudioSystem.isLineSupported(info)) {
    // 处理错误.
}
try {		// 获取并打开线路line.
    line = (TargetDataLine) AudioSystem.getLine(info);
    line.open(format);
} catch (LineUnavailableException ex) {
        // 处理错误.
    //... 
}

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

对于Port类,您可以在如下代码中使用Port.Info的静态实例:

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

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

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

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

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

请注意,这些方法中的每一个返回的数组元素都表示线路的唯一种类,而不一定是所有的线路。(不太会翻译,给原文:Note that the array returned by each of these methods indicates unique types of lines, not necessarily all the lines.)例如,如果混音器的两条线或两条不同混音器的线具有相同的Line.Info对象,则这两条线在返回的数组中将仅由一个Line.Info表示。

从混音器Mixer获得线路

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

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

这些方法返回特定混合器的所有Line.Info对象的数组。一旦获得数组,就可以遍历它们,调用MixergetLine方法来获取每一条线路,然后调用Lineopen方法来在你的程序中使用各条线路。

选择输入和输出端口

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

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

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

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

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

音频资源使用许可

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

  • 一个运行在小程序安全管理器下的小程序可以播放音频,但不能录制音频。
  • 没有安全管理器的应用程序可以播放和录制音频。
  • 使用默认安全管理器运行的应用程序可以播放但不能录制音频。

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

即使已被授予显式权限,小应用程序和应用程序也可以在与安全管理器一起运行时记录声音。

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

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值