保護されたユーザー モード オーディオ (PUMA)
Windows Vista では、保護されたユーザー モード オーディオ (PUMA) が導入されました。これは、保護された環境 (PE) のユーザー モード オーディオ エンジンであり、オーディオ処理とレンダリングのためのより安全な環境を提供します。 許容可能なオーディオ出力のみを有効にし、出力が確実に無効になるようにします。 PUMA の詳細については、「出力コンテンツ保護 と Windows Vista」を参照してください。
PUMA は Windows 7 用に更新され、次の機能が提供されました。
- S/PDIF エンドポイントでの SCMS (Serial Copying Management System) ビットと HDMI (High-Definition Multimedia Interface) エンドポイントでの HDCP (High-bandwidth Digital Content Protection) ビットの設定。
- 保護された環境 (PE) の外部で SCMS および HDMI 保護コントロールを有効にします。
オーディオ ドライバーでの DRM 保護
デジタル著作権管理 (DRM) は、セキュリティで保護されたコンテナーでメディア データをパッケージ化し、使用規則をコンテンツに添付する機能を提供します。 たとえば、コンテンツ プロバイダーは、 コピー防止 または デジタル出力無効化 を使用して、PC システムからの直接デジタル コピーや送信を無効にすることができます。
特定の Microsoft 製品のオーディオ スタックは、オーディオ コンテンツの再生を制御する使用規則を実装することで DRM をサポートしています。 保護されたコンテンツを再生するには、基になるオーディオ ドライバーが 信頼できるドライバー、つまり、DRMLevel 1300 のロゴ認定を受けたドライバーである必要があります。 信頼できるドライバーの開発については、Windows 2000 Driver Development Kit (DDK) 以降で定義されているインターフェイスを使用できます。 DDK で開発されたドライバーでは、DRM に必要なインターフェイスが実装されます。 詳細については、「デジタル著作権管理」を参照してください。
保護されたコンテンツをレンダリングするには、信頼されたドライバーが、オーディオ スタックを流れるコンテンツに コピー防止 と デジタル出力無効化 が設定されているか、またそれに応じて設定に応答するかをチェックする必要があります。
コピー防止ルール
コピー防止 は、直接デジタル コピーすることがシステムで許可されていないことを示します。 コンテンツに コピー防止 が設定されている場合のドライバーの新しい要求や要件を反映するために、WHQL テスト契約書の添付 B が更新されました。 Windows 7 では、組み込みの HD オーディオ クラス ドライバーは最新の要件に準拠しています。
コンテンツを別のコンポーネントに渡したり、DRM システムによって認証されていない不揮発性ストレージ メディアに格納したりできないことを確認するだけでなく、 コピー防止 が設定されている場合、オーディオ ドライバーは次のタスクを実行します。
- ドライバーは、HDMI エンドポイントで HDCP を有効にします。
- S/PDIF インターフェイスの場合、ドライバーは、L、Cp、およびカテゴリ コード ビットの組み合わせが、IEC 60958 で定義されているように、 "コピーなし" の SCMS 状態を示していることを検証します。
- L ビットは 0 に設定され、カテゴリ コードは "Digital Signal Mixer" に設定されます。
信頼できるオーディオ ドライバーによって使用される DRMRIGHTS 構造体は、KS オーディオ ピンまたはポート クラス ドライバーのストリーム オブジェクトに割り当てられた DRM コンテンツ権限を指定します。 CopyProtect メンバーは、オーディオ コンテンツに コピー防止 が設定されているかどうかを示します。
Windows 7 では、 CopyProtect の使用がより厳密になります。 ドライバーは、状態を "コピーなし" に設定することで、保護コントロールがオーディオ インターフェイスで設定されていること、HDMI 出力に HDCP が設定されていること、S/PDIF 出力に SCMS が設定されていることを確実にします。
デジタル出力無効化ルール
デジタル出力の無効化 は、システムからのコンテンツの送信が許可されていないことを示します。 Windows 7 では、HDMI エンドポイントで HDCP を有効にすることで、組み込みの HD オーディオ クラス ドライバーがこの設定に応答します。 これは、 コピー防止 設定に対するドライバーの応答に似ています。
保護された環境の外部でコンテンツ保護メカニズムを有効にする
PUMA は、保護された環境 (PE) 内の別のプロセスに存在します。 Windows Vista で、PUMA によって提供されるオーディオ コンテンツ保護コントロールを使用するには、メディア アプリケーションが PE 内にある必要があります。 MEDIA Foundation API のみが PE と対話できるため、コンテンツ保護コントロールは、Media Foundation API を使用してオーディオ コンテンツをストリーミングするアプリケーションに限定されます。
Windows 7 では、PUMA 出力信頼機関 (OTA) によって提供されるコンテンツ保護コントロールに、それらが PE に含まれているかや、オーディオ再生に Media Foundation API が使用されているかに関係なく、すべてのアプリケーションがアクセスできます。
実装の説明
オーディオ アプリケーションがオーディオ エンドポイントで SCMS または HDCP コンテンツ保護を制御するには、次の手順が必要です。 サポートされているオーディオ API は、DirectShow、DirectSound、WASAPI です。
このコード例では、次のインターフェイスを使用します。
メディア アプリケーションは、次のタスクを実行する必要があります。
開発環境を設定する。
必要なインターフェイスを参照し、次のコードに示すヘッダーを含めます。
#include <MMdeviceapi.h> // Device endpoint definitions #include <Mfidl.h> // OTA interface definitions
OTA インターフェイスを使用するための Mfuuid.lib にリンクさせます。
カーネル デバッガーとドライバー検証ツールを無効にして、認証チェック エラーが発生しないようにします。
次のコードに示すように、システム内のすべてのエンドポイントを列挙し、エンドポイント コレクションからターゲット エンドポイントを選択します。 デバイスの列挙の詳細については、「オーディオ デバイスの列挙」を参照してください。
BOOL IsDigitalEndpoint(IMMDevice *pDevice) { PROPVARIANT var; IPropertyStore *pProperties = NULL; EndpointFormFactor formfactor; BOOL bResult = FALSE; HRESULT hr = S_OK; PropVariantInit(&var); // Open endpoint properties hr = pDevice->OpenPropertyStore(STGM_READ, &pProperties); IF_FAILED_JUMP(hr, Exit); // get form factor hr = pProperties->GetValue(PKEY_AudioEndpoint_FormFactor, &var); IF_FAILED_JUMP(hr, Exit); formfactor = (EndpointFormFactor)var.uiVal; // DigitalAudioDisplayDevice is defined same as HDMI formfactor if ((SPDIF == formfactor) || (DigitalAudioDisplayDevice == formfactor)) { bResult = TRUE; } Exit: PropVariantClear(&var); SAFE_RELEASE(pProperties); return bResult; }
/****************************************************************** * * * GetDevice: Selects an endpoint that meets the requirements. * * * * ppDevice: Receives a pointer to an IMMDevice interface of * * the device's endpoint object * * * * * ******************************************************************/ HRESULT GetDevice(IMMDevice** ppDevice) { IMMDeviceEnumerator *pEnumerator = NULL; IMMDevice *pDevice = NULL; IMMDeviceCollection *pEndpoints = NULL; UINT cEndpoints = 0; const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); // Get enumerator for audio endpoint devices hr = CoCreateInstance( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator)); EXIT_ON_ERROR(hr) // Enumerate all active endpoints, hr = pEnumerator->EnumAudioEndpoints ( eRender, DEVICE_STATE_ACTIVE, &pEndpoints); EXIT_ON_ERROR(hr) hr = pEndpoints->GetCount(&cEndpoints); EXIT_ON_ERROR(hr) for (UINT i = 0; i < cEndpoints; i++) { hr = pEndpoints->Item(i, &pDevice); IF_FAILED_JUMP(hr, Exit); { // Select the endpoint that meets the requirements. // For example, SPDIF analog output or HDMI if (IsDigitalEndpoint(pDevice)) { *(ppDevice) = pDevice; (*ppDevice)->AddRef(); break; } } SAFE_RELEASE(pDevice); } Exit: if (FAILED(hr)) { // Notify error. // Not Shown. } SAFE_RELEASE(pEndpoints); SAFE_RELEASE(pEnumerator); }
列挙プロセスによって返されるエンドポイントへの IMMDevice ポインターを使用して、目的のオーディオ ストリーミング API をアクティブ化し、ストリーミングの準備をします。 オーディオ API が異なると、必要な準備も若干異なります。
- DShow オーディオ アプリケーションの場合:
IMMDevice::Activate を呼び出し、インターフェイス識別子として IID_IBaseFilter を指定して、DirectShow COM オブジェクトを作成します。
IUnknown *pDShowFilter = NULL; ... hr = pDevice->Activate ( IID_IBaseFilter, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDShowFilter));
デバイスによってアクティブ化されたこの COM オブジェクトを使用して DirectShow フィルター グラフを作成します。 このプロセスの詳細については、DirectShow SDK ドキュメントの「フィルター グラフの構築」を参照してください。
- DSound オーディオ アプリケーションの場合:
IMMDevice::Activate を呼び出し、インターフェイス識別子として IID_IDirectSound8 を指定して、DSound COM オブジェクトを作成します。
IDirectSound8 *pDSSound8; ... hr = pDevice->Activate ( IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDSSound8));
上記で作成した DSound オブジェクトを使用して、DSound をストリーミング用にプログラムします。 このプロセスの詳細については、 DirectSoundを参照してください。
- WASAPI の場合:
IMMDevice::Activate を呼び出し、インターフェイス識別子として IID_IAudioClient を指定して、 IAudioClient COM オブジェクトを作成します。
IAudioClient *pIAudioClient = NULL; ... hr = pDevice->Activate ( IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pIAudioClient));
オーディオ ストリームを開きます。
hr = pIAudioClient->Initialize(...);
- DShow オーディオ アプリケーションの場合:
オーディオ ストリーミングを開始します。
ストリームに保護ポリシーを設定します。
WASAPI クライアントの場合は、 IAudioClient::GetService を呼び出し、インターフェイス識別子として IID_IMFTrustedOutput を指定することで、ストリームの出力信頼機関 (OTA) オブジェクトの IMFTrustedOutput インターフェイスへの参照を取得します。
IMFTrustedOutput* pTrustedOutput = NULL; hr = pIAudioClient>GetService( __uuidof(IMFTrustedOutput), (void**)& pTrustedOutput);
IMFTrustedOutput::GetOutputTrustAuthorityCount を呼び出して、使用可能な OTA オブジェクトの数を取得します。
hr = pTrustedOutput->GetOutputTrustAuthorityCount(&m_dwCountOTA);
OTA コレクションを列挙し、アクション PEACTION_PLAY をサポートする OTA オブジェクトへの参照を取得します。 すべての OTA は、 IMFOutputTrustAuthority インターフェイスを公開します。
hr = pMFTrustedOutput->GetOutputTrustAuthorityByIndex(I, &pMFOutputTrustAuthority); hr = pMFOutputTrustAuthority->GetAction(&action)
IMFTrustedOutput インターフェイスを使用して、ストリームの保護ポリシーを設定します。
hr = pTrustedOutput ->SetPolicy(&pPolicy, nPolicy, &pbTicket, &cbTicket);
Note
EVR を使用している場合、 SetPolicy は MEPolicySet イベントを発生させ、OTA がポリシーを非同期的に適用することを示す MF_S_WAIT_FOR_POLICY_SET を返しします。 ただし、このコード例では、アプリケーションはオーディオ クライアントから OTA オブジェクトを取得した直接 WASAPI クライアントです (手順 5 a)。 EVR とは異なり、オーディオ クライアントやその他の WASAPI オブジェクトはメディア イベント ジェネレーターを実装しません。 メディア イベント ジェネレーターがない場合、 IMFTrustedOutput::SetPolicy は MF_S_WAIT_FOR_POLICY_SET を返しません。
オーディオ ストリーミングの開始後にオーディオ ポリシー設定を設定する必要があります。これを行わないと、 IMFTrustedOutput::GetOutputTrustAuthorityByIndex が失敗します。 また、この機能をサポートするには、基になるオーディオ ドライバーが 信頼できるドライバーである必要があります。
このコード例では、 pPolicy は、クライアント実装ポリシー オブジェクトの IMFOutputPolicy インターフェイスへのポインターです。 詳細については、 Media Foundation SDK のドキュメントを参照してください。
IMFOutputPolicy::GenerateRequiredSchemas メソッドの実装では、OTA が適用する必要がある出力保護システム (スキーマ) のコレクションを生成する必要があります。 各スキーマは GUID によって識別され、保護システムの構成データが含まれています。 コレクション内の保護システムが、信頼できるオーディオ ドライバーの使用に制限されていることを確認します。 この制限は、GUID、 MFPROTECTION_TRUSTEDAUDIODRIVERS、DISABLE、または CONSTRICTAUDIO によって識別されます。 MFPROTECTION_TRUSTEDAUDIODRIVERS を使用する場合、このスキーマの構成データは DWORD です。 スキーマと関連する構成データの詳細については、Protected Environment SDK のドキュメントを参照してください。
クライアントは、 IMFOutputSchema インターフェイスを実装することによって、スキーマ定義も提供する必要があります。 IMFOutputSchema::GetSchemaType は、スキーマ GUID として MFPROTECTION_TRUSTEDAUDIODRIVERS を取得します。 IMFOutputSchema::GetConfigurationData は、スキーマの構成データへのポインターを返します。
オーディオ ストリーミングを続行します。
ストリーミングを停止する前に、保護ポリシーが明確になっていることを確認します。
上記の関連ポリシー インターフェイス参照を解除します。
解除の呼び出しでは、以前に設定したポリシー設定がクリアされます。
Note
ストリームが再起動されるたびに、ストリームで保護ポリシーを再度設定する必要があります。 この手順は、手順 5-b で説明されています。
pMFOutputTrustAuthority->Release() pMFTrustedOutput->Release()
次のコード例は、ポリシーオブジェクトとスキーマオブジェクトの実装例を示しています。
//OTADsoundSample.cpp
#include <stdio.h>
#include <tchar.h>
#include <initguid.h>
#include <windows.h>
#include <mmreg.h>
#include <dsound.h>
#include <mfidl.h>
#include <Mmdeviceapi.h>
#include <AVEndpointKeys.h>
#include "OTADSoundSample.h"
#define STATIC_KSDATAFORMAT_SUBTYPE_AC3\
DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_DOLBY_AC3_SPDIF)
DEFINE_GUIDSTRUCT("00000092-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_AC3);
#define KSDATAFORMAT_SUBTYPE_AC3 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_AC3)
HRESULT SetOTAPolicy(IMMDevice *_pMMDevice,
DWORD _dwConfigData,
IMFTrustedOutput **_ppMFTrustedOutput,
IMFOutputTrustAuthority **ppMFOutputTrustAuthority,
IMFOutputPolicy **_ppMFOutputPolicy);
HRESULT ClearOTAPolicy(IMFTrustedOutput *_pMFTrustedOutput,
IMFOutputTrustAuthority *_pMFOutputTrustAuthority,
IMFOutputPolicy *_pMFOutputPolicy);
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
BOOL IsDigitalEndpoint(IMMDevice *pDevice)
{
PROPVARIANT var;
IPropertyStore *pProperties = NULL;
EndpointFormFactor formfactor;
BOOL bResult = FALSE;
HRESULT hr = S_OK;
PropVariantInit(&var);
// Open endpoint properties
hr = pDevice->OpenPropertyStore(STGM_READ, &pProperties);
IF_FAILED_JUMP(hr, Exit);
// get form factor
hr = pProperties->GetValue(PKEY_AudioEndpoint_FormFactor, &var);
IF_FAILED_JUMP(hr, Exit);
formfactor = (EndpointFormFactor)var.uiVal;
if ((SPDIF == formfactor) || (DigitalAudioDisplayDevice == formfactor))
{
bResult = TRUE;
}
Exit:
PropVariantClear(&var);
SAFE_RELEASE(pProperties);
return bResult;
}
HRESULT GetDigitalAudioEndpoint(IMMDevice** ppDevice)
{
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IMMDeviceCollection *pEndpoints = NULL;
UINT cEndpoints = 0;
HRESULT hr = S_OK;
*ppDevice = NULL;
// Get enumerator for audio endpoint devices.
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
IF_FAILED_JUMP(hr, Exit);
// Enumerate all active render endpoints,
hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEndpoints);
IF_FAILED_JUMP(hr, Exit);
hr = pEndpoints->GetCount(&cEndpoints);
IF_FAILED_JUMP(hr, Exit);
for (UINT i = 0; i < cEndpoints; i++)
{
hr = pEndpoints->Item(i, &pDevice);
IF_FAILED_JUMP(hr, Exit);
// Select the endpoint that meets the requirements.
// For example, SPDIF analog output or HDMI
// Not Shown.
if (IsDigitalEndpoint(pDevice))
{
*ppDevice = pDevice;
(*ppDevice)->AddRef();
break;
}
SAFE_RELEASE(pDevice);
}
Exit:
if (FAILED(hr))
{
// Notify error.
// Not Shown.
}
SAFE_RELEASE(pEndpoints);
SAFE_RELEASE(pEnumerator);
return hr;
}
//-------------------------------------------------------------------
int __cdecl wmain(int argc, char* argv[])
{
IMMDevice *pEndpoint=NULL;
HRESULT hr = S_OK;
// DSound related variables
IDirectSound8* DSSound8 = NULL;
IDirectSoundBuffer* DSBuffer = NULL;
DSBUFFERDESC DSBufferDesc;
WAVEFORMATEXTENSIBLE wfext;
WORD nChannels = 2;
DWORD nSamplesPerSec = 48000;
WORD wBitsPerSample = 16;
// OTA related variables
IMFTrustedOutput *pMFTrustedOutput=NULL;
IMFOutputPolicy *pMFOutputPolicy=NULL;
IMFOutputTrustAuthority *pMFOutputTrustAuthority=NULL;
DWORD dwConfigData=0;
// Initialize COM
hr = CoInitialize(NULL);
IF_FAILED_JUMP(hr, Exit);
printf("OTA test app for DSound\n");
hr = GetDigitalAudioEndpoint(&pEndpoint);
IF_FAILED_JUMP(hr, Exit);
if (pEndpoint)
{
printf("Found digital audio endpoint.\n");
}
//
// Active DSound interface
//
hr = pEndpoint->Activate(IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&DSSound8));
IF_FAILED_JUMP(hr, Exit);
nChannels = 2;
nSamplesPerSec = 48000;
wBitsPerSample = 16;
ZeroMemory(&wfext, sizeof(wfext));
wfext.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfext.Format.nChannels = nChannels;
wfext.Format.nSamplesPerSec = nSamplesPerSec;
wfext.Format.wBitsPerSample = wBitsPerSample;
wfext.Format.nBlockAlign = (nChannels * wBitsPerSample) / 8;
wfext.Format.nAvgBytesPerSec = nSamplesPerSec * ((nChannels * wBitsPerSample) / 8);
wfext.Format.cbSize = 22;
wfext.Samples.wValidBitsPerSample = wBitsPerSample;
wfext.dwChannelMask = 0x3;
wfext.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
#if 1
wfext.SubFormat = KSDATAFORMAT_SUBTYPE_AC3;
#endif
ZeroMemory(&DSBufferDesc, sizeof(DSBufferDesc));
DSBufferDesc.dwSize = sizeof(DSBufferDesc);
DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2;
DSBufferDesc.lpwfxFormat = (WAVEFORMATEX *)&wfext;
DSBufferDesc.dwBufferBytes = wfext.Format.nAvgBytesPerSec / 100;
HWND hwnd = GetForegroundWindow();
hr = DSSound8->SetCooperativeLevel(hwnd, DSSCL_PRIORITY);
IF_FAILED_JUMP(hr, Exit);
hr = DSSound8->CreateSoundBuffer(&DSBufferDesc, &DSBuffer, NULL);
IF_FAILED_JUMP(hr, Exit);
hr = DSBuffer->Play(0, 0, DSBPLAY_LOOPING);
IF_FAILED_JUMP(hr, Exit);
printf("Will set the following audio policy:\n");
printf("Test Certificate Enable: %s\n", TRUE ? "True" : "False");
printf("Copy OK: %s\n", FALSE ? "True" : "False");
printf("Digital Output Disable: %s\n", FALSE ? "True" : "False");
printf("DRM Level: %u\n", 1300);
// Set policy when the stream is in RUN state
dwConfigData = MAKE_MFPROTECTIONDATA_TRUSTEDAUDIODRIVERS2(TRUE, /*_bTestCertificateEnable*/
FALSE, /*_bDigitalOutputDisable*/
FALSE, /*_bCopyOK*/
1300 /*_dwDrmLevel*/);
hr = SetOTAPolicy(pEndpoint,dwConfigData, &pMFTrustedOutput, &pMFOutputTrustAuthority,&pMFOutputPolicy);
IF_FAILED_JUMP(hr, Exit);
//
// Perform all the necessary streaming operations here.
//
// stop audio streaming
DSBuffer->Stop();
// In order for the stream to restart successfully
// Need to release the following OutputTrust* interface to release audio endpoint
hr = ClearOTAPolicy(pMFTrustedOutput,pMFOutputTrustAuthority,pMFOutputPolicy);
IF_FAILED_JUMP(hr, Exit);
// After above release operations, the following Play() will succeed without device-in-use error message 0x8889000A
DSBuffer->SetCurrentPosition(0);
hr = DSBuffer->Play(0, 0, DSBPLAY_LOOPING);
IF_FAILED_JUMP(hr, Exit);
// Need to reset the new audio protection state because previous settings were gone with the ClearOTAPolicy call.
dwConfigData = MAKE_MFPROTECTIONDATA_TRUSTEDAUDIODRIVERS2(TRUE, /*_bTestCertificateEnable*/
FALSE, /*_bDigitalOutputDisable*/
FALSE, /*_bCopyOK*/
1300 /*_dwDrmLevel*/);
hr = SetOTAPolicy(pEndpoint,dwConfigData, &pMFTrustedOutput, &pMFOutputTrustAuthority,&pMFOutputPolicy);
IF_FAILED_JUMP(hr, Exit);
// Clean up setting before leaving your streaming app.
hr = ClearOTAPolicy(pMFTrustedOutput,pMFOutputTrustAuthority,pMFOutputPolicy);
IF_FAILED_JUMP(hr, Exit);
DSBuffer->SetCurrentPosition(0);
Exit:
SAFE_RELEASE(DSBuffer);
SAFE_RELEASE(DSSound8);
SAFE_RELEASE(pEndpoint);
CoUninitialize();
return 0;
}
//OTADSoundSample.h
// Macro defines
#define IF_FAILED_JUMP(_hresult, label) \
if(FAILED(_hresult)) \
{ \
goto label; \
}
#define SAFE_RELEASE(p) \
if (NULL != p) { \
(p)->Release(); \
(p) = NULL; \
}
#define IF_TRUE_ACTION_JUMP(condition, action, label) \
if(condition) \
{ \
action; \
goto label; \
}
// outputpolicy.h
class CTrustedAudioDriversOutputPolicy : public CMFAttributesImpl<IMFOutputPolicy>
{
friend
HRESULT CreateTrustedAudioDriversOutputPolicy(DWORD dwConfigData, IMFOutputPolicy **ppMFOutputPolicy);
private:
ULONG m_cRefCount;
DWORD m_dwConfigData;
GUID m_guidOriginator;
IMFOutputSchema *m_pOutputSchema;
CTrustedAudioDriversOutputPolicy(DWORD dwConfigData, HRESULT &hr);
~CTrustedAudioDriversOutputPolicy();
public:
// IUnknown methods
HRESULT STDMETHODCALLTYPE QueryInterface(/* [in] */ REFIID riid,/* [out] */ LPVOID *ppvObject);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
// IMFOutputPolicy methods
HRESULT STDMETHODCALLTYPE
GenerateRequiredSchemas(
/* [in] */ DWORD dwAttributes,
/* [in] */ GUID guidOutputSubType,
/* [in] */ GUID *rgGuidProtectionSchemasSupported,
/* [in] */ DWORD cProtectionSchemasSupported,
/* [annotation][out] */
__out IMFCollection **ppRequiredProtectionSchemas);
HRESULT STDMETHODCALLTYPE GetOriginatorID(/* [annotation][out] */ __out GUID *pguidOriginatorID);
HRESULT STDMETHODCALLTYPE GetMinimumGRLVersion(/* [annotation][out] */ __out DWORD *pdwMinimumGRLVersion);
}; // CTrustedAudioDriversOutputPolicy
class CTrustedAudioDriversOutputSchema : public CMFAttributesImpl<IMFOutputSchema>
{
friend
HRESULT CreateTrustedAudioDriversOutputSchema(
DWORD dwConfigData,
GUID guidOriginatorID,
IMFOutputSchema **ppMFOutputSchema
);
private:
CTrustedAudioDriversOutputSchema(DWORD dwConfigData, GUID guidOriginatorID);
~CTrustedAudioDriversOutputSchema();
ULONG m_cRefCount;
DWORD m_dwConfigData;
GUID m_guidOriginatorID;
public:
// IUnknown methods
HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [out] */ LPVOID *ppvObject
);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
// IMFOutputSchema methods
HRESULT STDMETHODCALLTYPE GetConfigurationData(__out DWORD *pdwVal);
HRESULT STDMETHODCALLTYPE GetOriginatorID(__out GUID *pguidOriginatorID);
HRESULT STDMETHODCALLTYPE GetSchemaType(__out GUID *pguidSchemaType);
}; // CTrustedAudioDriversOutputSchema
// outputpolicy.cpp
#include <windows.h>
#include <tchar.h>
#include <mfidl.h>
#include <atlstr.h>
#include <attributesbase.h>
#include "OTADSoundSample.h"
#include <Mmdeviceapi.h>
#include "OutputPolicy.h"
#define RETURN_INTERFACE(T, iid, ppOut) \
if (IsEqualIID(__uuidof(T), (iid))) { \
this->AddRef(); \
*(ppOut) = static_cast<T *>(this); \
return S_OK; \
} else {} (void)0
//--------------------------------------------------------------------------
// Implementation for CTrustedAudioDriversOutputPolicy
//--------------------------------------------------------------------------
// constructor
CTrustedAudioDriversOutputPolicy::CTrustedAudioDriversOutputPolicy(DWORD dwConfigData, HRESULT &hr)
: m_cRefCount(1), m_dwConfigData(dwConfigData), m_pOutputSchema(NULL)
{
hr = CoCreateGuid(&m_guidOriginator);
IF_FAILED_JUMP(hr, Exit);
hr = CreateTrustedAudioDriversOutputSchema(dwConfigData, m_guidOriginator, &m_pOutputSchema);
IF_FAILED_JUMP(hr, Exit);
Exit:
if (FAILED(hr))
{
printf("CreateTrustedAudioDriversOutputSchema failed: hr = 0x%08x", hr);
}
return;
}
// destructor
CTrustedAudioDriversOutputPolicy::~CTrustedAudioDriversOutputPolicy()
{
if (NULL != m_pOutputSchema)
{
m_pOutputSchema->Release();
}
}
// IUnknown::QueryInterface
HRESULT STDMETHODCALLTYPE
CTrustedAudioDriversOutputPolicy::QueryInterface(
/* [in] */ REFIID riid,
/* [out] */ LPVOID *ppvObject)
{
HRESULT hr = E_NOINTERFACE;
IF_TRUE_ACTION_JUMP((NULL == ppvObject), hr = E_POINTER, Exit);
*ppvObject = NULL;
RETURN_INTERFACE(IUnknown, riid, ppvObject);
RETURN_INTERFACE(IMFAttributes, riid, ppvObject);
RETURN_INTERFACE(IMFOutputPolicy, riid, ppvObject);
Exit:
return hr;
}
// IUnknown::AddRef
ULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputPolicy::AddRef()
{
ULONG uNewRefCount = InterlockedIncrement(&m_cRefCount);
return uNewRefCount;
}
// IUnknown::Release
ULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputPolicy::Release()
{
ULONG uNewRefCount = InterlockedDecrement(&m_cRefCount);
if (0 == uNewRefCount)
{
delete this;
}
return uNewRefCount;
}
// IMFOutputPolicy::GenerateRequiredSchemas
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputPolicy::GenerateRequiredSchemas
(
/* [in] */ DWORD dwAttributes,
/* [in] */ GUID guidOutputSubType,
/* [in] */ GUID *rgGuidProtectionSchemasSupported,
/* [in] */ DWORD cProtectionSchemasSupported,
/* [annotation][out] */
__out IMFCollection **ppRequiredProtectionSchemas
)
{
HRESULT hr = S_OK;
bool bTrustedAudioDriversSupported = false;
// if we've made it this far then the Output Trust Authority supports Trusted Audio Drivers
// create a collection and put our output policy in it
// then give that collection to the caller
CComPtr<IMFCollection> pMFCollection;
// sanity checks
IF_TRUE_ACTION_JUMP((NULL == ppRequiredProtectionSchemas), hr = E_POINTER, Exit);
*ppRequiredProtectionSchemas = NULL;
IF_TRUE_ACTION_JUMP((NULL == rgGuidProtectionSchemasSupported) && (0 != cProtectionSchemasSupported),
hr = E_POINTER, Exit);
// log all the supported protection schemas
for (DWORD i = 0; i < cProtectionSchemasSupported; i++)
{
if (IsEqualIID(MFPROTECTION_TRUSTEDAUDIODRIVERS, rgGuidProtectionSchemasSupported[i]))
{
bTrustedAudioDriversSupported = true;
}
}
if (!bTrustedAudioDriversSupported)
{
return HRESULT_FROM_WIN32(ERROR_RANGE_NOT_FOUND);
}
// create the collection
hr = MFCreateCollection(&pMFCollection);
if (FAILED(hr))
{
return hr;
}
// add our output policy to the collection
hr = pMFCollection->AddElement(m_pOutputSchema);
if (FAILED(hr))
{
return hr;
}
Exit:
// give the collection to the caller
return pMFCollection.CopyTo(ppRequiredProtectionSchemas); // increments refcount
}// GenerateRequiredSchemas
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputPolicy::GetOriginatorID(__out GUID *pguidOriginatorID)
{
if (NULL == pguidOriginatorID)
{
return E_POINTER;
}
*pguidOriginatorID = m_guidOriginator;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputPolicy::GetMinimumGRLVersion(__out DWORD *pdwMinimumGRLVersion)
{
if (NULL == pdwMinimumGRLVersion)
{
return E_POINTER;
}
*pdwMinimumGRLVersion = 0;
return S_OK;
}
//--------------------------------------------------------------------------
// Implementation for CTrustedAudioDriversOutputSchema
//--------------------------------------------------------------------------
// constructor
CTrustedAudioDriversOutputSchema::CTrustedAudioDriversOutputSchema
(
DWORD dwConfigData,
GUID guidOriginatorID
)
: m_cRefCount(1)
, m_dwConfigData(dwConfigData)
, m_guidOriginatorID(guidOriginatorID)
{}
// destructor
CTrustedAudioDriversOutputSchema::~CTrustedAudioDriversOutputSchema() {}
// IUnknown::QueryInterface
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::QueryInterface
(
/* [in] */ REFIID riid,
/* [out] */ LPVOID *ppvObject
)
{
HRESULT hr = E_NOINTERFACE;
IF_TRUE_ACTION_JUMP((NULL == ppvObject), hr = E_POINTER, Exit);
*ppvObject = NULL;
RETURN_INTERFACE(IUnknown, riid, ppvObject);
RETURN_INTERFACE(IMFAttributes, riid, ppvObject);
RETURN_INTERFACE(IMFOutputSchema, riid, ppvObject);
Exit:
return hr;
}
// IUnknown::AddRef
ULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::AddRef()
{
ULONG uNewRefCount = InterlockedIncrement(&m_cRefCount);
return uNewRefCount;
}
// IUnknown::Release
ULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::Release()
{
ULONG uNewRefCount = InterlockedDecrement(&m_cRefCount);
if (0 == uNewRefCount)
{
delete this;
}
return uNewRefCount;
}
// IMFOutputSchema::GetConfigurationData
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetConfigurationData(__out DWORD *pdwVal)
{
if (NULL == pdwVal) { return E_POINTER; }
*pdwVal = m_dwConfigData;
return S_OK;
}
// IMFOutputSchema::GetOriginatorID
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetOriginatorID(__out GUID *pguidOriginatorID)
{
if (NULL == pguidOriginatorID) { return E_POINTER; }
*pguidOriginatorID = m_guidOriginatorID;
return S_OK;
}
// IMFOutputSchema::GetSchemaType
HRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetSchemaType(__out GUID *pguidSchemaType)
{
if (NULL == pguidSchemaType) { return E_POINTER; }
*pguidSchemaType = MFPROTECTION_TRUSTEDAUDIODRIVERS;
return S_OK;
}
//---------------------------------------------------------------------------------------------------
//
// Other subroutine declarations
//
//---------------------------------------------------------------------------------------------------
HRESULT CreateTrustedAudioDriversOutputPolicy(DWORD dwConfigData, IMFOutputPolicy **ppMFOutputPolicy)
{
if (NULL == ppMFOutputPolicy)
{
return E_POINTER;
}
*ppMFOutputPolicy = NULL;
HRESULT hr = S_OK;
CTrustedAudioDriversOutputPolicy *pPolicy = new CTrustedAudioDriversOutputPolicy(dwConfigData, hr);
if (NULL == pPolicy)
{
return E_OUTOFMEMORY;
}
if (FAILED(hr))
{
delete pPolicy;
return hr;
}
*ppMFOutputPolicy = static_cast<IMFOutputPolicy *>(pPolicy);
return S_OK;
}// CreateTrustedAudioDriversOutputPolicy
HRESULT CreateTrustedAudioDriversOutputSchema
(
DWORD dwConfigData,
GUID guidOriginatorID,
IMFOutputSchema **ppMFOutputSchema)
{
if (NULL == ppMFOutputSchema)
{
return E_POINTER;
}
*ppMFOutputSchema = NULL;
CTrustedAudioDriversOutputSchema *pSchema =
new CTrustedAudioDriversOutputSchema(dwConfigData, guidOriginatorID);
if (NULL == pSchema)
{
return E_OUTOFMEMORY;
}
*ppMFOutputSchema = static_cast<IMFOutputSchema *>(pSchema);
return S_OK;
}// CreateTrustedAudioDriversOutputSchema
HRESULT SetOTAPolicy(IMMDevice *_pMMDevice,
DWORD _dwConfigData,
IMFTrustedOutput **_ppMFTrustedOutput,
IMFOutputTrustAuthority **ppMFOutputTrustAuthority,
IMFOutputPolicy **_ppMFOutputPolicy)
{
HRESULT hr = S_OK;
DWORD dwCountOfOTAs = 0;
bool bRet = false;
hr = CreateTrustedAudioDriversOutputPolicy(_dwConfigData, _ppMFOutputPolicy);
IF_FAILED_JUMP(hr, Exit);
// activate IMFTrustedOutput
hr = _pMMDevice->Activate(__uuidof(IMFTrustedOutput), CLSCTX_ALL, NULL,
(void**)_ppMFTrustedOutput);
IF_FAILED_JUMP(hr, Exit);
// get count of Output Trust Authorities on this trusted output
hr = (*_ppMFTrustedOutput)->GetOutputTrustAuthorityCount(&dwCountOfOTAs);
IF_FAILED_JUMP(hr, Exit);
// sanity check - fail on endpoints with no output trust authorities
IF_TRUE_ACTION_JUMP((0 == dwCountOfOTAs), hr = E_NOTFOUND, Exit);
printf("dwCountOfOTAs = %d\n", dwCountOfOTAs);
// loop over each output trust authority on the endpoint
for (DWORD i = 0; i < dwCountOfOTAs; i++)
{
// get the output trust authority
hr = (*_ppMFTrustedOutput)->GetOutputTrustAuthorityByIndex(i, ppMFOutputTrustAuthority);
IF_FAILED_JUMP(hr, Exit);
// log the purpose of the output trust authority
MFPOLICYMANAGER_ACTION action;
hr = (*ppMFOutputTrustAuthority)->GetAction(&action);
if (FAILED(hr))
{
return hr;
}
printf(" It's %s.", (PEACTION_PLAY==action) ? "PEACTION_PLAY" :
(PEACTION_COPY==action) ? "PEACTION_COPY" :
"Others");
// only PEACTION_PLAY Output Trust Authorities are relevant
if (PEACTION_PLAY != action)
{
printf("Skipping as the OTA action is not PEACTION_PLAY");
SAFE_RELEASE(*ppMFOutputTrustAuthority);
continue;
}
BYTE *pbTicket = NULL;
DWORD cbTicket = 0;
// audio ota does not support ticket, leaving it NULL is ok.
hr = (*ppMFOutputTrustAuthority)->SetPolicy(_ppMFOutputPolicy, 1, &pbTicket, &cbTicket);
IF_FAILED_JUMP(hr, Exit);
printf("SetPolicy succeeded.\n");
bRet = true;
break;
}// for each output trust authority
Exit:
if (bRet)
{
hr = S_OK;
}
if (FAILED(hr))
{
printf("failure code is 0x%0x\n", hr);
SAFE_RELEASE(*ppMFOutputTrustAuthority);
SAFE_RELEASE(*_ppMFTrustedOutput);
if (*_ppMFOutputPolicy)
{
delete (*_ppMFOutputPolicy);
}
}
return hr;
}
HRESULT ClearOTAPolicy(IMFTrustedOutput *_pMFTrustedOutput,
IMFOutputTrustAuthority *_pMFOutputTrustAuthority,
IMFOutputPolicy *_pMFOutputPolicy)
{
SAFE_RELEASE(_pMFOutputTrustAuthority);
SAFE_RELEASE(_pMFTrustedOutput);
if (_pMFOutputPolicy)
{
delete _pMFOutputPolicy;
}
return S_OK;
}
//OTADSoundSample.rc
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
// Version
#include <ntverp.h>
#define VER_FILETYPE VFT_DLL
#define VER_FILESUBTYPE VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR "Default Device Heuristic Dumper"
#define VER_INTERNALNAME_STR "DefaultDeviceDump.exe"
#define VER_ORIGINALFILENAME_STR "DefaultDeviceDump.exe"
#include "common.ver"
Sources file:
TARGETNAME=OTADSoundSample
TARGETTYPE=PROGRAM
TARGET_DESTINATION=retail
UMTYPE=console
UMENTRY=wmain
UMBASE=0x1000000
#_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_VISTA)
MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
USE_ATL=1
ATL_VER=70
USE_NATIVE_EH=1
USE_MSVCRT=1
C_DEFINES=-DUNICODE -D_UNICODE
INCLUDES=$(INCLUDES);
SOURCES=OTADSoundSample.cpp \
OTADSoundSample.rc \
outputpolicy.cpp\
TARGETLIBS=\
$(SDK_LIB_PATH)\advapi32.lib \
$(SDK_LIB_PATH)\kernel32.lib \
$(SDK_LIB_PATH)\User32.lib \
$(SDK_LIB_PATH)\shlwapi.lib \
$(SDK_LIB_PATH)\ole32.lib \
$(SDK_LIB_PATH)\oleaut32.lib \
$(SDK_LIB_PATH)\rpcrt4.lib \
$(SDK_LIB_PATH)\strmiids.lib \
$(SDK_LIB_PATH)\uuid.lib \
$(SDK_LIB_PATH)\SetupAPI.lib \
$(SDK_LIB_PATH)\mfplat.lib \