Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Windows Vista introducerade PROTECTED User Mode Audio (PUMA), ljudmotorn i användarläge i den skyddade miljön (PE) som ger en säkrare miljö för ljudbearbetning och återgivning. Det gör att endast acceptabla ljudutdata kan aktiveras och ser till att utdata inaktiveras på ett tillförlitligt sätt. Mer information om PUMA finns i Output Content Protection och Windows Vista.
PUMA har uppdaterats för Windows 7 för att tillhandahålla följande funktioner:
- Ange SCMS-bitar (Serial Copying Management System) på S/PDIF-slutpunkter och HDCP-bitar (High-Bandwidth Digital Content Protection) på High-Definition HDMI-slutpunkter (Multimedia Interface).
- Aktivera SCMS- och HDMI-skyddskontroller utanför en skyddad miljö (PE).
DRM-skydd i ljuddrivrutiner
Digital Rights Management (DRM) ger möjlighet att paketera mediedata i en säker container och koppla användningsregler till innehållet. Innehållsleverantören kan till exempel använda Copy Protection eller Digital Output Inaktivera för att inaktivera digitala direktkopior eller överföring från pc-systemet.
Ljudstacken i vissa Microsoft-produkter stöder DRM genom att implementera användningsreglerna som styr uppspelningen av ljudinnehållet. Om du vill spela upp det skyddade innehållet måste den underliggande ljuddrivrutinen vara en betrodd drivrutin; drivrutinen måste vara logotypcertifierad för DRMLevel 1300. Om du vill ha information om hur du utvecklar betrodda drivrutiner kan du använda gränssnitt som definieras i Windows 2000 Driver Development Kit ("DDK") eller senare. Drivrutiner som utvecklats med DDK implementerar nödvändiga gränssnitt för DRM. Mer information finns i Digital Rights Management.
Om du vill återge det skyddade innehållet måste den betrodda drivrutinen kontrollera om Copy Protection och Digital Output Disable har angetts för innehållet som flödar genom ljudstacken och svara på inställningarna i enlighet med detta.
Kopiera skyddsregel
Copy Protection- anger att digitala direktkopior inte tillåts i systemet. Bilaga B till WHQL-testavtalet har uppdaterats för att återspegla de nya förväntningarna och kraven för en drivrutin när Copy Protection- anges på innehållet. För Windows 7 uppfyller den inbyggda hd-ljudklassdrivrutinen de senaste kraven.
Förutom att säkerställa att innehåll inte tillåts att skickas till en annan komponent eller lagras på något icke-överförbar lagringsmedium som inte autentiseras av DRM-systemet, utför ljuddrivrutinen följande uppgifter när Copy Protection- anges:
- Drivrutinen aktiverar HDCP på HDMI-slutpunkter.
- För S/PDIF-gränssnitt verifierar drivrutinen att kombinationen av bitarna L, Cp och Kategorikod anger SCMS-tillståndet "Kopiera aldrig", enligt definitionen i IEC 60958.
- L-biten är inställd på 0 och kategorikoden är inställd på "Digital Signal Mixer".
DRMRIGHTS- struktur, som används av betrodda ljuddrivrutiner, anger DRM-innehållsrättigheterna som tilldelats en KS-ljudstift eller till en portklassdrivrutins strömobjekt. Medlemmen CopyProtect anger om Copy Protection- har angetts för ljudinnehållet.
För Windows 7 är användningen av CopyProtect striktare. Drivrutinen ser till att skyddskontrollerna ställs in på ljudgränssnitten, HDCP har ställts in för HDMI-utdata och SCMS har ställts in för S/PDIF-utdata genom att ange tillståndet "Kopiera aldrig".
Inaktivera regel för digitala utdata
Digital Output Disable anger att innehållet inte får överföras ut ur systemet. I Windows 7 svarar den inbyggda HD-ljudklassdrivrutinen på den här inställningen genom att aktivera HDCP på HDMI-slutpunkter. Detta liknar drivrutinens svar på inställningen Copy Protection.
Aktivera mekanismer för innehållsskydd utanför en skyddad miljö
PUMA finns i en separat process i den skyddade miljön (PE). Om du vill använda de kontroller för ljudinnehållsskydd som erbjuds av PUMA i Windows Vista måste ett medieprogram finnas i en PE. Eftersom endast Media Foundation-API:er kan interagera med en PE begränsas innehållsskyddskontrollerna till program som använder Media Foundation-API:er för att strömma ljudinnehåll.
I Windows 7 kan alla program komma åt de innehållsskyddskontroller som tillhandahålls av PUMA Output Trust Authority (OTA), oavsett om de finns i en PE eller använder Media Foundation-API:er för ljuduppspelning.
Implementeringsinstruktioner
Följande steg krävs för att ett ljudprogram ska kunna styra SCMS- eller HDCP-innehållsskydd på en ljudslutpunkt. Ljud-API:er som stöds är DirectShow, DirectSound och WASAPI.
I den här exempelkoden används följande gränssnitt.
Medieprogrammet måste utföra följande uppgifter.
Konfigurera utvecklingsmiljön.
Referera till de gränssnitt som krävs, inkludera rubrikerna som visas i följande kod.
#include <MMdeviceapi.h> // Device endpoint definitions #include <Mfidl.h> // OTA interface definitions
Länka till Mfuuid.lib för att använda OTA-gränssnitten.
Inaktivera kernelfelsökaren och drivrutinsverifieraren för att undvika autentiseringskontrollfel.
Räkna upp alla slutpunkter i systemet och välj målslutpunkten från slutpunktssamlingen, enligt följande kod. Mer information om hur du räknar upp enheter finns i Räkna upp ljudenheter.
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); }
Använd IMMDevice- pekare till slutpunkten som returneras av uppräkningsprocessen för att aktivera önskat API för ljudströmning och förbereda för strömning. Olika ljud-API:er kräver lite olika förberedelser.
- För DShow-ljudprogram:
Skapa ett DirectShow COM-objekt genom att anropa IMMDevice::Aktivera och ange IID_IBaseFilter som gränssnittsidentifierare.
IUnknown *pDShowFilter = NULL; ... hr = pDevice->Activate ( IID_IBaseFilter, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDShowFilter));
Skapa ett DirectShow-filterdiagram med det här COM-objektet aktiverat av enheten. Mer information om den här processen finns i "Skapa filterdiagrammet" i DirectShow SDK-dokumentationen.
- För DSound-ljudprogram:
Skapa ett DSound COM-objekt genom att anropa IMMDevice::Aktivera och ange IID_IDirectSound8 som gränssnittsidentifierare.
IDirectSound8 *pDSSound8; ... hr = pDevice->Activate ( IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDSSound8));
Använd DSound-objekt som skapats ovan för att programmera DSound för ångande. Mer information om den här processen finns i DirectSound.
- För WASAPI:
Skapa ett IAudioClient- COM-objekt genom att anropa IMMDevice::Aktivera och ange IID_IAudioClient som gränssnittsidentifierare.
IAudioClient *pIAudioClient = NULL; ... hr = pDevice->Activate ( IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pIAudioClient));
Öppna ljudströmmen.
hr = pIAudioClient->Initialize(...);
- För DShow-ljudprogram:
Starta ljuduppspelning.
Ange skyddsprincipen i strömmen.
För WASAPI-klienter får du en referens till IMFTrustedOutput--gränssnittet för OTA-objektet (output trust authority) för dataströmmen genom att anropa IAudioClient::GetService och ange IID_IMFTrustedOutput som gränssnittsidentifierare.
IMFTrustedOutput* pTrustedOutput = NULL; hr = pIAudioClient>GetService( __uuidof(IMFTrustedOutput), (void**)& pTrustedOutput);
Hämta antalet tillgängliga OTA-objekt genom att anropa IMFTrustedOutput::GetOutputTrustAuthorityCount.
hr = pTrustedOutput->GetOutputTrustAuthorityCount(&m_dwCountOTA);
Räkna upp OTA-samlingen och hämta en referens till OTA-objektet som stöder åtgärden PEACTION_PLAY. Alla OTA:er exponerar gränssnittet IMFOutputTrustAuthority.
hr = pMFTrustedOutput->GetOutputTrustAuthorityByIndex(I, &pMFOutputTrustAuthority); hr = pMFOutputTrustAuthority->GetAction(&action)
Använd IMFTrustedOutput--gränssnittet för att ange skyddsprincipen på strömmen.
hr = pTrustedOutput ->SetPolicy(&pPolicy, nPolicy, &pbTicket, &cbTicket);
Not
Om du använder EVR genererar SetPolicy händelsen MEPolicySet och returnerar MF_S_WAIT_FOR_POLICY_SET för att indikera att OTA tillämpar principen asynkront. I den här exempelkoden är programmet dock en direkt WASAPI-klient som hämtade OTA-objektet från ljudklienten (steg 5 a). Till skillnad från EVR implementerar inte en ljudklient och andra WASAPI-objekt mediehändelsegeneratorer. Utan mediahändelsegeneratorer returnerar IMFTrustedOutput::SetPolicy inte MF_S_WAIT_FOR_POLICY_SET.
Inställningar för ljudprinciper måste anges när ljuduppspelningen startar, annars IMFTrustedOutput::GetOutputTrustAuthorityByIndex misslyckas. För att stödja den här funktionen måste den underliggande ljuddrivrutinen också vara en betrodd drivrutin.
I exempelkoden är pPolicy en pekare till IMFOutputPolicy-gränssnittet för ett klient implementerat principobjekt. Mer information finns i dokumentationen Media Foundation SDK.
I implementeringen av metoden IMFOutputPolicy::GenerateRequiredSchemas måste en samling utdataskyddssystem (scheman) genereras som OTA måste tillämpa. Varje schema identifieras av ett GUID och innehåller konfigurationsdata för skyddssystemet. Kontrollera att skyddssystemen i samlingen är begränsade till att använda betrodda ljuddrivrutiner. Den här begränsningen identifieras av GUID, MFPROTECTION_TRUSTEDAUDIODRIVERS, DISABLE eller CONSTRICTAUDIO. Om MFPROTECTION_TRUSTEDAUDIODRIVERS används är konfigurationsdata för det här schemat ett DWORD. Mer information om scheman och relaterade konfigurationsdata finns i dokumentationen om SDK för skyddad miljö.
Klienten måste också ange schemadefinitionen genom att implementera IMFOutputSchema--gränssnittet. IMFOutputSchema::GetSchemaType hämtar MFPROTECTION_TRUSTEDAUDIODRIVERS som schema-GUID. IMFOutputSchema::GetConfigurationData returnerar en pekare till schemats konfigurationsdata.
Fortsätt med ljuduppspelning.
Kontrollera att skyddsprincipen är tydlig innan du stoppar direktuppspelningen.
Släpp referenserna för det relaterade principgränssnittet ovan.
Versionsanropen rensar de tidigare angivna principinställningarna.
Not
Varje gång en ström startas om måste skyddsprincipen anges igen i dataströmmen. Proceduren beskrivs i steg 5d.
pMFOutputTrustAuthority->Release() pMFTrustedOutput->Release()
Följande kodexempel visar en exempelimplementering av princip- och schemaobjekten.
//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 \