Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
System Windows Vista wprowadził chroniony dźwięk w trybie użytkownika (PUMA), aparat audio w trybie użytkownika w środowisku chronionym (PE), który zapewnia bezpieczniejsze środowisko do przetwarzania i renderowania dźwięku. Umożliwia włączenie tylko akceptowalnych danych wyjściowych dźwięku i zapewnienie niezawodnego wyłączenia danych wyjściowych. Aby uzyskać więcej informacji na temat funkcji PUMA, zobacz Output Content Protection i Windows Vista.
Funkcja PUMA została zaktualizowana dla systemu Windows 7 w celu zapewnienia następujących funkcji:
- Ustawianie bitów systemu zarządzania kopiowaniem szeregowym (SCMS) w punktach końcowych S/PDIF i bitach ochrony zawartości cyfrowej (HDCP) o wysokiej przepustowości na punktach końcowych interfejsu multimedialnego (HDMI) High-Definition.
- Włączanie kontroli ochrony SCMS i HDMI poza środowiskiem chronionym (PE).
Ochrona DRM w sterownikach audio
Usługa Digital Rights Management (DRM) umożliwia pakowanie danych multimedialnych w bezpiecznym kontenerze i dołączanie reguł użycia do zawartości. Na przykład dostawca zawartości może użyć usługi Copy Protection lub digital output Disable, aby wyłączyć bezpośrednie kopie cyfrowe lub transmisję z systemu komputerowego.
Stos audio w niektórych produktach firmy Microsoft obsługuje drM, implementując reguły użycia, które zarządzają odtwarzaniem zawartości audio. Aby odtworzyć chronioną zawartość, źródłowy sterownik audio musi być zaufanym sterownikiem; oznacza to, że sterownik musi być certyfikowany do drMLevel 1300. Aby uzyskać informacje na temat tworzenia zaufanych sterowników, można użyć interfejsów zdefiniowanych w zestawie Windows 2000 Driver Development Kit ("DDK") lub nowszym. Sterowniki opracowane za pomocą zestawu DDK implementują niezbędne interfejsy do drM. Aby uzyskać więcej informacji, zobacz Digital Rights Management.
Aby renderować chronioną zawartość, zaufany sterownik musi sprawdzić, czy ochrona przed kopiowaniem i cyfrowe dane wyjściowe Wyłącz są ustawione na zawartość przepływającą przez stos audio i odpowiednio reagować na ustawienia.
Reguła ochrony kopiowania
copy Protection wskazuje, że bezpośrednie kopie cyfrowe nie są dozwolone w systemie. Załącznik B do umowy testowej WHQL został zaktualizowany w celu odzwierciedlenia nowych oczekiwań i wymagań sterownika, gdy ochrony przed kopiowaniem jest ustawiona na zawartość. W przypadku systemu Windows 7 wbudowany sterownik klasy audio HD spełnia najnowsze wymagania.
Oprócz zapewnienia, że zawartość nie może być przekazywana do innego składnika lub przechowywana na dowolnym nieużywanej nośniku pamięci masowej, który nie jest uwierzytelniany przez system DRM, sterownik audio wykonuje następujące zadania podczas ochrony przed kopiowaniem:
- Sterownik włącza procesor HDCP w punktach końcowych HDMI.
- W przypadku interfejsów S/PDIF sterownik sprawdza, czy kombinacja bitów L, Cp i Category Code wskazuje stan SCMS "Copy Never", zgodnie z definicją w IEC 60958.
- Bit L jest ustawiony na wartość 0, a kod kategorii jest ustawiony na wartość "Digital Signal Mixer".
Struktura DRMRIGHTS używana przez zaufane sterowniki audio określa prawa do zawartości DRM przypisane do numeru PIN audio KS lub do obiektu strumienia sterownika klasy portów. Element członkowski CopyProtect wskazuje, czy ochrony przed kopiowaniem jest ustawiona na zawartości audio.
W systemie Windows 7 użycie CopyProtect jest bardziej rygorystyczne. Sterownik zapewnia, że kontrolki ochrony są ustawione na interfejsach dźwiękowych, HDCP jest ustawiony na wyjście HDMI, a SCMS jest ustawiony dla danych wyjściowych S/PDIF, ustawiając stan na "Kopiuj nigdy".
Reguła wyłączania danych wyjściowych cyfrowych
Digital Output Disable wskazuje, że zawartość nie może być przesyłana z systemu. W systemie Windows 7 wbudowany sterownik klasy audio HD reaguje na to ustawienie, włączając hdCP w punktach końcowych HDMI. Jest to podobne do odpowiedzi sterownika na ustawienie Copy Protection.
Włączanie mechanizmów ochrony zawartości poza chronionym środowiskiem
Funkcja PUMA znajduje się w osobnym procesie w środowisku chronionym (PE). W systemie Windows Vista, aby używać kontrolek ochrony zawartości audio oferowanych przez PUMA, aplikacja multimediów musi znajdować się w PE. Ponieważ tylko interfejsy API programu Media Foundation mogą współdziałać z interfejsem PE, mechanizmy kontroli ochrony zawartości są ograniczone do aplikacji korzystających z interfejsów API programu Media Foundation w celu strumieniowego przesyłania zawartości audio.
W systemie Windows 7 każda aplikacja może uzyskiwać dostęp do mechanizmów ochrony zawartości udostępnianych przez urząd puMA Output Trust Authority (OTA), niezależnie od tego, czy znajdują się one w środowisku PE, czy przy użyciu interfejsów API programu Media Foundation do odtwarzania audio.
Instrukcje dotyczące implementacji
Poniższe kroki są wymagane, aby aplikacja audio mogła kontrolować ochronę zawartości SCMS lub HDCP w punkcie końcowym audio. Obsługiwane interfejsy API audio to DirectShow, DirectSound i WASAPI.
Ten przykładowy kod używa następujących interfejsów.
Aplikacja multimediów musi wykonywać następujące zadania.
Konfigurowanie środowiska projektowego.
Odwołaj się do wymaganych interfejsów, dołącz nagłówki pokazane w poniższym kodzie.
#include <MMdeviceapi.h> // Device endpoint definitions #include <Mfidl.h> // OTA interface definitionsPołącz się z biblioteką Mfuuid.lib, aby użyć interfejsów OTA.
Wyłącz debuger jądra i weryfikator sterowników, aby uniknąć błędów sprawdzania uwierzytelniania.
Wylicz wszystkie punkty końcowe w systemie i wybierz docelowy punkt końcowy z kolekcji punktów końcowych, jak pokazano w poniższym kodzie. Aby uzyskać więcej informacji na temat wyliczania urządzeń, zobacz Wyliczanie urządzeń audio.
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); }Użyj wskaźnika IMMDevice do punktu końcowego zwróconego przez proces wyliczania, aby aktywować żądany interfejs API przesyłania strumieniowego audio i przygotować się do przesyłania strumieniowego. Różne interfejsy API audio wymagają nieco innego przygotowania.
- W przypadku aplikacji audio DShow:
Utwórz obiekt COM DirectShow, wywołując IMMDevice::Activate i określając IID_IBaseFilter jako identyfikator interfejsu.
IUnknown *pDShowFilter = NULL; ... hr = pDevice->Activate ( IID_IBaseFilter, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDShowFilter));Skompiluj wykres filtru DirectShow z tym obiektem COM aktywowanym przez urządzenie. Aby uzyskać więcej informacji na temat tego procesu, zobacz "Tworzenie wykresu filtru" w dokumentacji zestawu SDK DirectShow.
- W przypadku aplikacji audio DSound:
Utwórz obiekt COM DSound, wywołując IMMDevice::Activate i określając IID_IDirectSound8 jako identyfikator interfejsu.
IDirectSound8 *pDSSound8; ... hr = pDevice->Activate ( IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDSSound8));Użyj obiektu DSound utworzonego powyżej, aby programować DSound do parowania. Aby uzyskać więcej informacji na temat tego procesu, zobacz DirectSound.
- W przypadku interfejsu WASAPI:
Utwórz obiekt IAudioClient COM, wywołując IMMDevice::Activate i określając IID_IAudioClient jako identyfikator interfejsu.
IAudioClient *pIAudioClient = NULL; ... hr = pDevice->Activate ( IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pIAudioClient));Otwórz strumień audio.
hr = pIAudioClient->Initialize(...);
- W przypadku aplikacji audio DShow:
Uruchom przesyłanie strumieniowe audio.
Ustaw zasady ochrony w strumieniu.
W przypadku klientów WASAPI uzyskaj odwołanie do interfejsu IMFTrustedOutput interfejsu wyjściowego urzędu zaufania (OTA) dla strumienia, wywołując IAudioClient::GetService i określając IID_IMFTrustedOutput jako identyfikator interfejsu.
IMFTrustedOutput* pTrustedOutput = NULL; hr = pIAudioClient>GetService( __uuidof(IMFTrustedOutput), (void**)& pTrustedOutput);Pobierz liczbę dostępnych obiektów OTA, wywołując IMFTrustedOutput::GetOutputTrustAuthorityCount.
hr = pTrustedOutput->GetOutputTrustAuthorityCount(&m_dwCountOTA);Wylicz kolekcję OTA i uzyskaj odwołanie do obiektu OTA obsługującego PEACTION_PLAY akcji. Wszystkie otA uwidacznia interfejs IMFOutputTrustAuthority.
hr = pMFTrustedOutput->GetOutputTrustAuthorityByIndex(I, &pMFOutputTrustAuthority); hr = pMFOutputTrustAuthority->GetAction(&action)Użyj interfejsu IMFTrustedOutput, aby ustawić zasady ochrony w strumieniu.
hr = pTrustedOutput ->SetPolicy(&pPolicy, nPolicy, &pbTicket, &cbTicket);Nuta
Jeśli używasz protokołu EVR, SetPolicy zgłasza zdarzenie MEPolicySet i zwraca MF_S_WAIT_FOR_POLICY_SET, aby wskazać, że usługa OTA będzie wymuszać zasady asynchronicznie. Jednak w tym przykładowym kodzie aplikacja jest bezpośrednim klientem WASAPI, który pobrał obiekt OTA z klienta audio (krok 5 a). W przeciwieństwie do oprogramowania EVR klient audio i inne obiekty WASAPI nie implementują generatorów zdarzeń multimediów. Bez generatorów zdarzeń multimedialnych IMFTrustedOutput::SetPolicy nie zwraca MF_S_WAIT_FOR_POLICY_SET.
Ustawienia zasad dźwięku należy ustawić po uruchomieniu przesyłania strumieniowego audio, w przeciwnym razie IMFTrustOutput::GetOutputTrustAuthorityByIndex kończy się niepowodzeniem. Ponadto w celu obsługi tej funkcji podstawowy sterownik audio musi być zaufanym sterownikiem.
W przykładowym kodzie pPolicy jest wskaźnikiem do interfejsu IMFOutputPolicy obiektu zasad implementowanych przez klienta. Aby uzyskać więcej informacji, zobacz dokumentację zestawu SDK Media Foundation.
W implementacji metody IMFOutputPolicy::GenerateRequiredSchemas należy wygenerować kolekcję systemów ochrony danych wyjściowych (schematów), które muszą wymuszać OTA. Każdy schemat jest identyfikowany przez identyfikator GUID i zawiera dane konfiguracji systemu ochrony. Upewnij się, że systemy ochrony w kolekcji są ograniczone do używania zaufanych sterowników audio. To ograniczenie jest identyfikowane przez identyfikator GUID, MFPROTECTION_TRUSTEDAUDIODRIVERS, DISABLE lub CONSTRICTAUDIO. Jeśli MFPROTECTION_TRUSTEDAUDIODRIVERS jest używana, dane konfiguracji dla tego schematu są DWORD. Aby uzyskać więcej informacji na temat schematów i powiązanych danych konfiguracji, zobacz dokumentację zestawu SDK środowiska chronionego.
Klient musi również podać definicję schematu, implementując interfejs IMFOutputSchema. IMFOutputSchema::GetSchemaType pobiera MFPROTECTION_TRUSTEDAUDIODRIVERS jako identyfikator GUID schematu. IMFOutputSchema::GetConfigurationData zwraca wskaźnik do danych konfiguracji schematu.
Kontynuuj przesyłanie strumieniowe audio.
Przed zatrzymaniem przesyłania strumieniowego upewnij się, że zasady ochrony są jasne.
Zwolnij powyższe odwołania do powiązanego interfejsu zasad.
Wydanie wywołuje czyszczenie poprzednio ustawionych ustawień zasad.
Nuta
Za każdym razem, gdy strumień jest uruchamiany ponownie, zasady ochrony muszą być ponownie ustawione na strumieniu. Procedura jest opisana w kroku 5-d.
pMFOutputTrustAuthority->Release() pMFTrustedOutput->Release()
W poniższych przykładach kodu przedstawiono przykładową implementację obiektów zasad i schematu.
//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 \