第 3 章: オーディオシステムリソースへのアクセス


注 -

  1. 現在、Sun の JavaSound リファレンス実装では Port は実装されていません (http://developer.java.sun.com/developer/bugParade/bugs/4384401.html を参照)。
  2. 開始点から終了点まで Clip の一部分をループしようとしても正常に動作しません (http://developer.java.sun.com/developer/bugParade/bugs/4386052.html を参照)。

JavaTM Sound API では柔軟なシステム構成手法を採用しています。 1 台のコンピュータにさまざまな種類のオーディオデバイス (ミキサー) をインストールできます。 この API では、インストールされているデバイスの種類とその機能についての前提事項はほとんどありません。 その代わりに、利用可能なオーディオコンポーネント、およびそれらのコンポーネントにプログラムからアクセスする方法をシステムから通知させます。

この章では、プログラムがコンピュータにインストールされているサンプリングオーディオリソースを確認する方法、および利用可能なリソースへのアクセスを得る方法について説明します。 この場合のリソースには、ミキサーおよびミキサーに所属する各種のラインが含まれます。

AudioSystem クラス

AudioSystem クラスは、組み込みサービスおよびサードパーティプロバイダが個別にインストールしたサービスを含む、オーディオコンポーネントの情報センターの役目をします。 AudioSystem は、インストールされたサンプリングオーディオリソースにアプリケーションプログラムがアクセスするためのエントリポイントになります。 AudioSystem に問い合わせて、どのようなリソースがインストールされているかを調べ、次にそれらのコンポーネントへのアクセスを取得できます。 たとえば、アプリケーションプログラムはまず特定の構成 (前章のラインの説明で示した入出力構成など) を持つミキサーがあるかどうかを AudioSystem に問い合わせることができます。 次に、プログラムはミキサーからデータラインなどを取得できます。

アプリケーションプログラムが AudioSystem から取得できるリソースには次のようなものがあります。

情報オブジェクト

Java Sound API のクラスの中には、関連インタフェースについて有用な情報を提供するものがあります。 たとえば、Mixer.Info は、インストールされているミキサーのベンダー、名前、説明、バージョンなどの詳細情報を提供します。 Line.Info は特定のラインのクラスを取得します。 Line.Info のサブクラスには Port.InfoDataLine.Info があり、Port.Info は特定のポート、DataLine.Info は特定のデータラインに関する詳細を取得します。 これらの各クラスについては、このあとそれぞれの節で説明します。 Info オブジェクトと、そのオブジェクトが記述するミキサーまたはラインオブジェクトを混同しないよう注意してください。

ミキサーの取得

通常、Java Sound API を使用するプログラムは最初の仕事の 1 つとして、ミキサー、またはミキサーのラインの少なくとも 1 本を取得します。それによりコンピュータの内外にサウンドを入出力できます。 使用するプログラムで特定の種類のミキサーが必要な場合や、利用可能なミキサーのリストを表示してユーザがミキサーを選択できるようにする場合があります。 どちらの場合も、インストールされているミキサーの種類を知る必要があります。 AudioSystem には次のメソッドがあります。

    static Mixer.Info[] getMixerInfo()
このメソッドから返される各 Mixer.Info オブジェクトは、インストールされているミキサーの種類を示します。 通常、システムにある特定の種類のインスタンスは、多くても 1 つです。 仮に数種類のミキサーが指定されていても、返された配列内にはその種類の Mixer.Info は 1 つしかありません。 アプリケーションプログラムは、Mixer.Info オブジェクトを繰り返し処理し、必要なミキサーを探します。 Mixer.Info には、ミキサーの種類を示す次の文字列が含まれています。

これらは任意の文字列なので、特定のミキサーを必要とするアプリケーションプログラムは、予期すべき文字列と文字列の比較対象を知っていなければなりません。 ミキサーの製造元は、この情報を文書化すべきですが、 一般には特定のミキサーを必要としない場合が多く、この場合はアプリケーションプログラムはすべての Mixer.Info オブジェクトの文字列を表示し、ユーザがミキサーを選択するようにします。

適切なミキサーが見つかったら、アプリケーションプログラムは次の AudioSystem メソッドを呼び出して、目的のミキサーを取得します。

    static Mixer getMixer(Mixer.Info info)
プログラムが特定の機能を持つミキサーを必要とするが、特定のベンダーが製造したミキサーでなくてもよい場合があります。 また、ユーザが選択すべきミキサーを知らない可能性もあります。 このような場合は、Mixer.Info オブジェクト内の情報はあまり役に立ちません。 その代わり、getMixerInfo から返されるすべての Mixer.Info オブジェクトを繰り返し処理し、getMixer を繰り返し呼び出すことによりミキサーを取得し、そのミキサーの機能を調べることができます。 たとえば、ミキシング済みのオーディオデータを特定の本数のターゲットデータラインに同時に書き込むことのできるミキサーが必要だとします。 この場合は、この Mixer メソッドを使って各ミキサーに問い合わせを行います。

int getMaxLines(Line.Info info)

ここで、Line.InfoTargetDataLine を指定します。 Line.Info クラスについては、次の節で説明します。

目的の種類のラインの取得

ラインを取得する方法には次の 2 種類があります。

AudioSystem からラインを直接取得する方法

ここでは、ミキサーをまだ取得しておらず、使用するプログラムが特定の種類のラインだけを必要とする単純なものであるとします。ミキサーの詳細情報は重要ではありません。 この場合は、AudioSystem メソッドを使用できます。

    static Line getLine(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 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 オブジェクトを取得します。 ほかの種類のラインを取得する場合にも、これに類似したコードを使用できます。 SourceDataLine または Clip の場合は、そのクラスを line 変数のクラスとして TargetDataLine の代わりに使用し、DataLine.Info コンストラクタの最初の引数にもそのクラスを使用します。

Port の場合は、次のようなコードの中で Port.Info の static インスタンスを使用できます。

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)
これらの各メソッドから返される配列内の各オブジェクトは、ラインの一意の種類を示しますが、必ずしもすべてのラインが示されるとは限りません。 たとえば、1 つのミキサーのラインのうちの 2 本または、異なるミキサーの 2 本のラインが同一のLine.Info オブジェクトを持つ場合は、その 2 本のラインは返された配列の中の 1 つの Line.Info によって表されます。

ミキサーからラインを取得する方法

Mixer インタフェースには、すでに説明したソースラインとターゲットラインのためのさまざまな AudioSystem のアクセスメソッドがあります。 これらの Mixer メソッドには、AudioSystem のメソッドと同様に Line.Info 引数を取るものもありますが、引数を取らない形式を含むものもあります。

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

これらのメソッドは、特定のミキサーのすべての Line.Info オブジェクトの配列を返します。 配列を取得したら、繰り返し処理して、MixergetLine メソッドを呼び出して各ラインを取得し、次に Lineopen メソッドを行って各ラインをプログラムで使用できるよう予約します。

入出力ポートの選択

前節では目的の種類のラインを取得する方法を説明しましたが、ほかの種類のラインとポートについても同じことが当てはまります。 Line.Info 引数を取る AudioSystem (または Mixer) メソッドであるgetSourceLineInfogetTargetLineInfoPort.Info オブジェクトを渡すことにより、すべてのソース (入力) ポートとターゲット (出力) ポートを取得できます。 次に、返されたオブジェクト配列を繰り返し処理して MixergetLine メソッドを呼び出し、各ポートを取得します。

次に、Lineopen メソッドを呼び出して各 Port をオープンします。 ポートのオープンとは、そのポートをオンにすること、つまりポートを介したサウンドの往来を許可することを意味します。 また、ポートを取得する前にいくつかのポートがすでに取得されている場合は、サウンドの移動に使用されるポートをクローズすることができます。 プラットフォームによってはデフォルトですべてのポートが解放されています。また、ユーザかシステム管理者がほかのアプリケーションプログラムまたは OS のソフトウェアを使って特定のポートをオンまたはオフに設定している場合があります。

警告: ここで説明した方法でポートをオープンすると、特定のポートを選択し、そのポートに実際にサウンドが往来しているかどうかを確認することができます。 ただし、これはユーザフレンドリーではない印象を与える場合があります。 たとえば、同僚の迷惑にならないように、ユーザがスピーカのポートをオフにしていることがあります。 ユーザの意に反して突然音楽が鳴り響いたら、ユーザはびっくりしてしまいます。 別の例として、盗聴を防ぐために、ユーザの知らない間にコンピュータのマイクロフォンがオンにならないようにする場合があります。 一般に、ユーザインタフェースによって表現されるユーザの意図に対してプログラムが応答する場合以外は、プログラムでポートのオープンやクローズを行わないようにすることをお勧めします。 ユーザまたは OS がすでに選択している設定を尊重してください。

事前にポートのオープンやクローズを行わなくても、そのポートが取り付けられているミキサーは正しく機能します。 たとえば、ミキサーのすべての出力ポートがクローズしていても、サウンドの再生を開始してオーディオ出力ミキサーに送ることができます。 データはミキサーに流れ、再生はブロックされません。 ただし、ユーザには何も聞こえません。 ユーザが出力ポートをオープンすると、その時点でポートから出るサウンドが聞こえるようになります。再生が及んだメディア内のどこからでも開始できます。

また、ミキサーに特定のポートがあるかどうかを知るためにポートにアクセスする必要はありません。 たとえば、ミキサーが実際にオーディオ出力ミキサーかどうかを知るために、getTargetLineInfo を呼び出して、そのミキサーが出力ポートを持っているかどうかを調べることができます。 設定 (オープンまたはクローズ状態、ポートに備わっているコントロールの設定など) を変更する場合を除き、ポート自体にアクセスする必要はありません。

オーディオリソースを使用するためのアクセス権

Java Sound API には、AudioPermission クラスがあります。そのサンプリングオーディオシステムに対してアプレット (またはセキュリティマネージャ付きで実行しているアプリケーションプログラム) が実行できるアクセスの種類を示します。 録音のアクセス権は別々に制御されます。 不正な盗聴などのセキュリティ上の危険を防ぐため、アクセス権の許可は注意して行ってください。 デフォルトでは、アプレットとアプリケーションには次のようなアクセス権が許可されています。

一般に、アプレットはセキュリティマネージャの監視下で実行されており、録音は許可されません。 これに対し、アプリケーションはセキュリティマネージャの自動インストールは行わず、録音が可能です。 ただし、アプリケーションに対してデフォルトのセキュリティマネージャが明示的に呼び出された場合は、アプリケーションは録音を許可されません。

アプレットもアプリケーションも、録音のための明示的なアクセス権が与えられている場合は、セキュリティマネージャ付きで実行していても録音が可能です。

プログラムに録音 (または再生) のアクセス権が与えられていない場合は、ラインをオープンしようとすると例外がスローされます。 アクセス権は API によって変更できないので、この場合は、例外を受け取ってユーザに問題を報告する以外にプログラムでできることはありません。 それ以外に何かを行っても、安全が保証されていないので無意味です。 一般に、アクセス権は 1 つまたは複数のポリシー設定ファイルに設定されています。ユーザまたはシステム管理者はテキストエディタまたは Policy Tool プログラムを使ってこの設定ファイルを編集することができます。

セキュリティとアクセス権の詳細は、 http://java.sun.com/products/jdk/1.3/docs/guide/security の「Security Architecture」と「Policy Permissions」、および Java Tutorial http://java.sun.com/docs/books/tutorial/ の「Specialized Trails」にあるセキュリティに関する項目を参照してください。