オーディオ モジュール通信の実装
オーディオ モジュールは、比較的アトミックな関数を実行する個別のオーディオ処理ロジックです。 オーディオ モジュールは、オーディオ ドライバーまたはオーディオ DSP に配置できます。 オーディオ モジュールの例としては、DSP ベースのオーディオ処理があります。
Windows 10 リリース 1703 以降では、ユニバーサル Windows プラットフォーム (UWP) アプリとカーネル モード デバイス ドライバーからの通信をサポートする API と DDI の両方があります。
このトピックでは、カーネル デバイス ドライバーでのオーディオ モジュール通信の実装について説明します。
UWP アプリを使用してオーディオ デバイス モジュールからコマンドを送信し、変更通知を受信する方法については、「オーディオ デバイス モジュールの構成とクエリ」をご覧ください。
オーディオ モジュールを使用する理由
OEM は通常、システムに構成アプリケーションをバンドルします。これにより、お客様はこのオーディオ システムの側面を制御し、ユーザーの好みに合わせて調整できます。 オーディオ サブシステムには、オンホスト オーディオ処理オブジェクト、ハードウェア DSP 処理、(すべてオーディオ コーデック自体に加えて) スマート アンプなどの特殊なハードウェアなどのさまざまなコンポーネントを含めることができます。 ほとんどの場合、これらのコンポーネントは異なるベンダーによって作成および販売されます。 これまで、IHV は、互いに統合し、個々のコンポーネント間で情報を送信するための独自のプライベート API を作成してきました。 既存の WIN32 構成アプリケーションでは、これらのプライベート API が利用されます。
ユニバーサル Windows プラットフォーム (UWP) には、1 つのアプリケーションをさまざまなデバイスで実行できる一連の API が用意されています。 UWP には、Windows 10 で実行されているアプリケーションに関するお客様の期待に応える新しいルック アンド フィールも導入されました。 多くの OEM は、UWP でオーディオ構成アプリケーションを構築したいと考えています。 ただし、UWP の主要なセキュリティ機能 (AppContainer サンドボックス) により、アプリケーションからオーディオ サブシステム内の他のコンポーネントへの通信ができなくなります。 これにより、構成アプリにより以前使用されていたプライベート API が UWP でアクセスできなくなります。
Windows 10 リリース 1703 以降、オーディオ モジュール UWP API を使用すると、構成アプリケーションおよびユーザー モード コンポーネントが、新しい KS プロパティ セットを通じて検出可能なカーネルおよびハードウェア レイヤー内のモジュールと通信できるようになります。 オーディオ IHV と ISV は、Windows によって提供される明確に定義されたインターフェイスを使って、ハードウェア モジュールと通信できるアプリケーションとサービスを記述できます。 オーディオ モジュール API について詳しくは、「Windows.Media.Devices 名前空間」をご覧ください。
オーディオ モジュールの定義
これらの定義は、オーディオ モジュールに固有です。
任期 | 定義 |
---|---|
オーディオ モジュール | 比較的アトミックな関数を実行する個別のオーディオ処理ロジック。 オーディオ ドライバーまたはオーディオ DSP に存在する可能性があります。 オーディオ モジュールの例として、オーディオ処理オブジェクト (APO) があります。 |
一般的なオーディオ定義
これらの定義は通常、オーディオ ドライバーを操作するときに使用されます。
任期 | 定義 |
---|---|
HSA | ハードウェア サポート アプリケーション |
UWP | ユニバーサル Windows プラットフォーム |
AP | オーディオ処理オブジェクト |
DSP | デジタル信号処理 |
任期 | 定義 |
---|---|
OEM | Original Equipment Manufacturer (相手先ブランド供給) |
IHV | 独立系ハードウェア ベンダー |
ISV | 独立系ソフトウェア ベンダー |
Architecture
オーディオ モジュールは、ユーザー モードとカーネル モードのオーディオ コンポーネントの間でメッセージを送信するための、Windows OS でサポートされるメカニズムを配置します。 重要な違いは、オーディオ モジュールがトランスポート パイプラインを標準化している点です。 そのトランスポート経由で通信プロトコルを確立するのではなく、プロトコルを定義するために ISV と IHV に依存しています。 その目的は、既存のサード パーティ製の設計を、わずかな変更だけでオーディオ モジュールに簡単に移行できるようにすることです。
この図は、Audio Module API を介してユーザー アプリケーションからオーディオ ドライバーにオーディオ データがどのように流れるかを示しています。
デバイス モジュールとストリーム モジュールは、クライアント プロセスからアクセスするか、AudioDG から APO に提供されるストリーム モジュール インターフェイスを使用して AudioDG で実行されている APO からアクセスするかに応じて存在します。 オーディオ エンジンとオーディオ デバイス グラフ (AudioDG) の一般的な情報については、「Windows オーディオ アーキテクチャ」を参照してください。
ドライバーは、 IoReportTargetDeviceChangeAsynchronous 関数を介してモジュールの変更を Windows.Media.Devices に通知します。この関数はモジュール API からクライアント プロセスまたは APO へのコールバックに変換されます。
オーディオ モジュール API は、KS wave フィルターと初期化された KS ピン (ストリーム) の 2 つの異なるターゲット メソッドを介してモジュールにアクセスできます。 特定のモジュールへの配置とアクセスは、実装に固有です。
HSA や他のアプリケーションは、フィルター ハンドルを介して使用可能なモジュールにのみアクセスできます。 ストリームに読み込まれる個々の API は、ストリーム対象のオーディオ モジュールにアクセスできる唯一のオブジェクトです。 API の詳細については、「Windows オーディオ処理オブジェクト」を参照してください。
コマンドの送信
パラメーターのクエリと変更を行うオーディオ モジュール クライアントの手段として、カーネル内のオーディオ モジュールとオーディオ サブシステムのハードウェア コンポーネントにコマンドを送信できます。 オーディオ モジュール API のコマンド構造は、疎に定義されており、モジュールを検出して自身を識別する方法が形式化されています。 ただし、関連する ISV および IHV によって詳細なコマンド構造を設計および実装し、送信できるメッセージと予想される応答のプロトコルを確立する必要があります。
オーディオ モジュール クライアントへのモジュール通知
さらに、オーディオ ミニポートには、クライアントが特定のモジュールの通知をサブスクライブしている場合に、オーディオ モジュール クライアントに通知して情報を渡す方法も用意されています。 これらの通知で渡される情報は、オーディオ モジュール API によって定義されるのではなく、ISV または IHV によって定義されます。
有効化、無効化、および一般的なトポロジ情報
オーディオ モジュール API は、モジュールにコマンドを列挙して送信する方法を定義します。 ただし、API は、オーディオ モジュール クライアントが特定のモジュールを有効または無効にする方法を明示的に定義しません。 さらに、クライアントが相互に関連してトポロジ情報やモジュールの配置を見つける方法は確立されません。 IHV と ISV は、この機能が必要かどうかを判断し、この機能の実装方法を決めることができます。
推奨される方法として、グローバル ドライバー モジュールを公開できます。 グローバル ドライバー モジュールは、これらのトポロジ固有の要求のカスタム コマンドを処理します。
オーディオ モジュール DDI
カーネル ストリーミング オーディオ モジュールのプロパティ
KSPROPSETID_AudioModule によって識別される新しい KS プロパティ セットは、オーディオ モジュールに固有の 3 つのプロパティに対して定義されています。
PortCls ミニポート ドライバーは、ヘルパー インターフェイスが提供されていないため、各プロパティの応答を直接処理する必要があります。
ksmedia.h:
#define STATIC_KSPROPSETID_AudioModule \
0xc034fdb0, 0xff75, 0x47c8, 0xaa, 0x3c, 0xee, 0x46, 0x71, 0x6b, 0x50, 0xc6
DEFINE_GUIDSTRUCT("C034FDB0-FF75-47C8-AA3C-EE46716B50C6", KSPROPSETID_AudioModule);
#define KSPROPSETID_AudioModule DEFINE_GUIDNAMED(KSPROPSETID_AudioModule)
typedef enum {
KSPROPERTY_AUDIOMODULE_DESCRIPTORS = 1,
KSPROPERTY_AUDIOMODULE_COMMAND = 2,
KSPROPERTY_AUDIOMODULE_NOTIFICATION_DEVICE_ID = 3,
} KSPROPERTY_AUDIOMODULE;
オーディオ モジュール記述子
KSPROPERTY_AUDIOMODULE_DESCRIPTORS プロパティのサポートにより、ドライバーがオーディオ モジュールに対応していると識別されます。 プロパティはフィルター ハンドルまたはピン ハンドルを通じてクエリを実行でき、KSPROPERTY は DeviceIoControl 呼び出しの入力バッファーとして渡されます。 KSAUDIOMODULE_DESCRIPTOR は、オーディオ ハードウェア内の各モジュールを記述するように定義されています。 これらの記述子の配列は、この要求に応答して返されます
ksmedia.h:
#define AUDIOMODULE_MAX_NAME_SIZE 128
typedef struct _KSAUDIOMODULE_DESCRIPTOR
{
GUID ClassId;
ULONG InstanceId;
ULONG VersionMajor;
ULONG VersionMinor;
WCHAR Name[AUDIOMODULE_MAX_NAME_SIZE];
} KSAUDIOMODULE_DESCRIPTOR, *PKSAUDIOMODULE_DESCRIPTOR;
詳しくは、「KSAUDIOMODULE_DESCRIPTOR」をご覧ください。
オーディオ モジュール コマンド
KSPROPERTY_AUDIOMODULE_COMMAND プロパティのサポートにより、オーディオ モジュール クライアントはカスタム コマンドを送信して、オーディオ モジュールでパラメータに対するクエリを実行して、パラメーターを設定できます。 プロパティはフィルター ハンドルまたはピン ハンドルを介して送信でき、KSAUDIOMODULE_PROPERTY は DeviceIoControl 呼び出しの入力バッファーとして渡されます。 必要に応じて、クライアントは、カスタム コマンドを送信するために、入力バッファー内の KSAUDIOMODULE_PROPERTY の直後に追加情報を送信できます。
ksmedia.h:
#define AUDIOMODULE_MAX_DATA_SIZE 64000
typedef struct _KSPAUDIOMODULE_PROPERTY
{
KSPROPERTY Property;
GUID ClassId;
ULONG InstanceId;
} KSAUDIOMODULE_PROPERTY, *PKSPAUDIOMODULE_PROPERTY;
詳細については、「KSAUDIOMODULE_PROPERTY」を参照してください。
オーディオ モジュール通知デバイス ID
信号通知に対してミニポートを有効にして、オーディオ モジュール クライアントに情報を渡すには、KSPROPERTY_AUDIOMODULE_NOTIFICATION_DEVICE_ID のサポートが必要です。 この ID の有効期間は、Windows オーディオ スタックに公開されてアクティブになっているオーディオ デバイスの有効期間に関連付けられます。 プロパティはフィルター ハンドルまたはピン ハンドルを介して送信でき、KSPROPERTY は DeviceIoControl 呼び出しの入力バッファーとして渡されます。
詳細については、「KSAUDIOMODULE_PROPERTY」を参照してください。
PortCls ヘルパー - オーディオ モジュール通知
ドライバー開発者がオーディオ モジュール クライアントに通知を送信できるよう、新しいポート インターフェイスが追加されました。
PortCls.h:
typedef struct _PCNOTIFICATION_BUFFER
{
UCHAR NotificationBuffer[1];
} PCNOTIFICATION_BUFFER, *PPCNOTIFICATION_BUFFER;
DECLARE_INTERFACE_(IPortClsNotifications,IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN() // For IUnknown
STDMETHOD_(NTSTATUS, AllocNotificationBuffer)
( THIS_
_In_ POOL_TYPE PoolType,
_In_ USHORT NumberOfBytes,
_Out_ PPCNOTIFICATION_BUFFER* NotificationBuffer
) PURE;
STDMETHOD_(void, FreeNotificationBuffer)
( THIS_
_In_ PPCNOTIFICATION_BUFFER NotificationBuffer
) PURE;
STDMETHOD_(void, SendNotificationBuffer)
( THIS_
_In_ const GUID* NotificationId,
_In_ PPCNOTIFICATION_BUFFER NotificationBuffer
) PURE;
};
//
// Audio module notification definitions.
//
#define STATIC_KSNOTIFICATIONID_AudioModule \
0x9C2220F0, 0xD9A6, 0x4D5C, 0xA0, 0x36, 0x57, 0x38, 0x57, 0xFD, 0x50, 0xD2
DEFINE_GUIDSTRUCT("9C2220F0-D9A6-4D5C-A036-573857FD50D2", KSNOTIFICATIONID_AudioModule);
#define KSNOTIFICATIONID_AudioModule DEFINE_GUIDNAMED(KSNOTIFICATIONID_AudioModule)
typedef struct _KSAUDIOMODULE_NOTIFICATION {
union {
struct {
GUID DeviceId;
GUID ClassId;
ULONG InstanceId;
ULONG Reserved;
} ProviderId;
LONGLONG Alignment;
};
} KSAUDIOMODULE_NOTIFICATION, *PKSAUDIOMODULE_NOTIFICATION;
詳細については、以下を参照してください:
IPortClsNotifications::AllocNotificationBuffer
IPortClsNotifications::FreeNotificationBuffer
IPortClsNotifications::SendNotificationBuffer
呼び出しシーケンス
ミニポートは、作成し、通知を送信するポートを呼び出します。 この図は、一般的な呼び出しシーケンスを示しています。