Mode Audio Protégé en Mode Utilisateur (PUMA).
Windows Vista a introduit le Mode Audio Protégé en Mode Utilisateur (PUMA), le moteur audio en mode utilisateur dans l’Environnement Protégé (PE) qui offre un environnement plus sûr pour le traitement et le rendu audio. Il permet uniquement l’activation des sorties audio acceptables et garantit que les sorties sont désactivées de manière fiable. Pour plus d’informations sur PUMA, veuillez consulter la section Protection du Contenu de Sortie et Windows Vista.
PUMA a été mis à jour pour Windows 7 pour offrir les fonctionnalités suivantes :
- Définition des bits du Système de Gestion de la Copie en Série (SCMS) sur les points de terminaison S/PDIF et des bits de Protection de Contenu Numérique à Large Bande Passante (HDCP) sur les points de terminaison de l’Interface Multimédia Haute Définition (HDMI).
- Activation des contrôles de protection SCMS et HDMI en dehors d’un Environnement Protégé (PE).
Protection DRM dans les pilotes audio.
La Gestion des Droits Numériques (DRM) permet de conditionner les données multimédias dans un conteneur sécurisé et d’attacher des règles d’utilisation au contenu. Par exemple, le fournisseur de contenu pourrait utiliser Protection contre la copie ou Désactivation de la sortie numérique pour désactiver les copies numériques directes ou la transmission hors du système PC.
La pile audio dans certains produits Microsoft prend en charge la DRM en implémentant les règles d’utilisation qui régissent la lecture du contenu audio. Pour lire le contenu protégé, le pilote audio sous-jacent doit être un pilote de confiance ; c’est-à-dire que le pilote doit être certifié par le logo pour DRMLevel 1300. Pour obtenir des informations sur le développement de pilotes de confiance, vous pouvez utiliser les interfaces définies dans le Kit de Développement de Pilotes Windows 2000 (« DDK ») et les versions ultérieures. Les pilotes développés avec le DDK mettront en œuvre les interfaces nécessaires à la DRM. Pour plus d’informations, veuillez consulter la section Gestion des droits numériques.
Pour rendre le contenu protégé, le pilote de confiance doit vérifier si Protection contre la copie et Désactivation de la sortie numérique sont définis sur le contenu circulant dans la pile audio et réagir en conséquence.
Règle de protection contre la copie
La protection contre la copie indique que les copies numériques directes ne sont pas autorisées sur le système. L’Annexe B de l’Accord de Testing WHQL a été mise à jour pour refléter les nouvelles attentes et exigences d’un pilote lorsque Protection contre la copie est activée sur le contenu. Pour Windows 7, le pilote de classe audio HD intégré est conforme aux dernières exigences.
En plus de s’assurer que le contenu n’est pas autorisé à passer à un autre composant ou à être stocké sur un support de stockage non volatile qui n’est pas authentifié par le système DRM, le pilote audio effectue les tâches suivantes lorsque Protection contre la copie est activée :
- Le pilote active HDCP sur les points de terminaison HDMI.
- Pour les interfaces S/PDIF, le pilote valide que la combinaison des bits L, Cp et du Code de catégorie indique un état SCMS de « Copy Never », comme défini dans l’IEC 60958.
- Le bit L est réglé sur 0 et le Code de catégorie est réglé sur « Mélangeur de signaux numériques » (Digital Signal Mixer).
La structure DRMRIGHTS , utilisée par les pilotes audio de confiance, spécifie les droits de contenu DRM attribués à une broche audio KS ou à un objet de flux du pilote de classe de port. Le membre CopyProtect indique si la Protection contre la copie est définie sur le contenu audio.
Pour Windows 7, l’utilisation de CopyProtect est plus stricte. Le pilote s’assure que les contrôles de protection sont définis sur les interfaces audio, que HDCP est activé pour la sortie HDMI et que SCMS est réglé pour la sortie S/PDIF en définissant l’état sur «Copy Never ».
Règle de désactivation de la sortie numérique
La Désactivation de la sortie numérique indique que le contenu n’est pas autorisé à être transmis hors du système. Dans Windows 7, le pilote de classe audio HD intégré répond à ce paramètre en activant HDCP sur les points de terminaison HDMI. Cela est similaire à la réponse du pilote au paramètre de Protection contre la copie.
Activation de mécanismes de protection du contenu en dehors d’un environnement protégé
PUMA réside dans un processus séparé dans l’Environnement Protégé (PE). Dans Windows Vista, pour utiliser les contrôles de protection du contenu audio offerts par PUMA, une application multimédia doit être dans un PE. Étant donné que seules les API Media Foundation peuvent interagir avec un PE, les contrôles de protection du contenu sont limités aux applications utilisant les API Media Foundation pour diffuser du contenu audio.
Dans Windows 7, n’importe quelle application peut accéder aux contrôles de protection de contenu fournis par l’Autorité de Confiance de Sortie PUMA (OTA), qu’elles soient ou non dans un PE ou utilisant les API Media Foundation pour la lecture audio.
Instructions d’implémentation
Les étapes suivantes sont nécessaires pour qu’une application audio contrôle la protection de contenu SCMS ou HDCP sur un point de terminaison audio. Les API audio prises en charge sont DirectShow, DirectSound, et WASAPI.
Cet exemple de code utilise les interfaces suivantes.
L’application multimédia doit effectuer les tâches suivantes.
Configurez l’environnement de développement.
Faire référence aux interfaces requises, inclure les en-têtes indiqués dans le code suivant.
#include <MMdeviceapi.h> // Device endpoint definitions #include <Mfidl.h> // OTA interface definitions
Lier à Mfuuid.lib pour utiliser les interfaces OTA.
Désactiver le débogueur de noyau et le vérificateur de pilote pour éviter toute erreur de vérification d’authentification.
Enumérer tous les points de terminaison dans le système et sélectionner le point de terminaison cible de la collection de points de terminaison, comme indiqué dans le code suivant. Pour plus d’informations sur l’énumération des périphériques, veuillez consulter la section Énumération des périphériques 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); }
Utilisez le pointeur IMMDevice sur le point de terminaison retourné par le processus d’énumération pour activer l’API de diffusion audio souhaitée et préparer la diffusion. Différentes API audio nécessitent une préparation légèrement différente.
- Pour les applications audio DShow :
Créez un objet COM DirectShow en appelant IMMDevice::Activate et en spécifiant IID_IBaseFilter comme identificateur d’interface.
IUnknown *pDShowFilter = NULL; ... hr = pDevice->Activate ( IID_IBaseFilter, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDShowFilter));
Construisez un graphe de filtre DirectShow avec cet objet COM activé par le périphérique. Pour plus d’informations sur ce processus, consultez la « Construction du graphe de filtre » dans la documentation SDK de DirectShow.
- Pour les applications audio DSound :
Créez un objet COM DSound en appelant IMMDevice::Activate et en spécifiant IID_IDirectSound8 comme identificateur d’interface.
IDirectSound8 *pDSSound8; ... hr = pDevice->Activate ( IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pDSSound8));
Utilisez l’objet DSound créé ci-dessus pour programmer DSound pour la diffusion. Pour plus d’informations sur ce processus, consultez DirectSound.
- Pour WASAPI :
Créez un objet COM IAudioClient en appelant IMMDevice::Activate et en spécifiant IID_IAudioClient comme identificateur d’interface.
IAudioClient *pIAudioClient = NULL; ... hr = pDevice->Activate ( IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pIAudioClient));
Ouvrez le flux audio.
hr = pIAudioClient->Initialize(...);
- Pour les applications audio DShow :
Démarrez la diffusion audio.
Définissez la politique de protection sur le flux.
Pour les clients WASAPI, obtenez une référence à l’interface IMFTrustedOutput de l’objet autorité de confiance de sortie (OTA) pour le flux en appelant IAudioClient::GetService et en spécifiant IID_IMFTrustedOutput comme identificateur d’interface.
IMFTrustedOutput* pTrustedOutput = NULL; hr = pIAudioClient>GetService( __uuidof(IMFTrustedOutput), (void**)& pTrustedOutput);
Obtenez un compte des objets OTA disponibles en appelant IMFTrustedOutput::GetOutputTrustAuthorityCount.
hr = pTrustedOutput->GetOutputTrustAuthorityCount(&m_dwCountOTA);
Enumérez la collection OTA et obtenez une référence à l’objet OTA qui prend en charge l’action PEACTION_PLAY. Tous les OTAs exposent l’interface IMFOutputTrustAuthority.
hr = pMFTrustedOutput->GetOutputTrustAuthorityByIndex(I, &pMFOutputTrustAuthority); hr = pMFOutputTrustAuthority->GetAction(&action)
Utilisez l’interface IMFTrustedOutput pour définir la politique de protection sur le flux.
hr = pTrustedOutput ->SetPolicy(&pPolicy, nPolicy, &pbTicket, &cbTicket);
Remarque
Si vous utilisez l’EVR, SetPolicy déclenche l’événement MEPolicySet et retourne MF_S_WAIT_FOR_POLICY_SET pour indiquer que l’OTA appliquera la politique de manière asynchrone. Cependant, dans cet exemple de code, l’application est un client WASAPI direct qui a récupéré l’objet OTA du client audio (Étape 5 a). Contrairement à l’EVR, un client audio et d’autres objets WASAPI ne mettent pas en œuvre des générateurs d’événements multimédia. Sans générateurs d’événements multimédia, IMFTrustedOutput::SetPolicy ne retourne pas MF_S_WAIT_FOR_POLICY_SET.
Les paramètres de politique audio doivent être définis après le démarrage de la diffusion audio, sinon IMFTrustedOutput::GetOutputTrustAuthorityByIndex échoue. De plus, pour prendre en charge cette fonctionnalité, le pilote audio sous-jacent doit être un pilote de confiance.
Dans le code d’exemple, pPolicy est un pointeur vers l’interface IMFOutputPolicy d’un objet de politique implémenté par le client. Pour obtenir des informations, consultez la documentation du SDK de Media Foundation.
Dans l’implémentation de la méthode IMFOutputPolicy::GenerateRequiredSchemas, une collection des systèmes de protection de sortie (schémas) doit être générée que l’OTA doit appliquer. Chaque schéma est identifié par un GUID et contient des données de configuration pour le système de protection. Assurez-vous que les systèmes de protection dans la collection sont restreints à l’utilisation de pilotes audio de confiance. Cette restriction est identifiée par le GUID, MFPROTECTION_TRUSTEDAUDIODRIVERS, DISABLE, ou CONSTRICTAUDIO. Si MFPROTECTION_TRUSTEDAUDIODRIVERS est utilisé, les données de configuration pour ce schéma sont un DWORD. Pour plus d’informations sur les schémas et les données de configuration associées, consultez la documentation SDK de l’Environnement Protégé.
Le client doit également fournir la définition du schéma, en implémentant l’interface IMFOutputSchema. IMFOutputSchema::GetSchemaType récupère MFPROTECTION_TRUSTEDAUDIODRIVERS comme le GUID du schéma. IMFOutputSchema::GetConfigurationData retourne un pointeur vers les données de configuration du schéma.
Continuez la diffusion audio.
Assurez-vous que la politique de protection est effacée avant d’arrêter la diffusion.
Libérez les références d’interface de politique liées ci-dessus.
Les appels de libération effacent les paramètres de politique précédemment définis.
Remarque
Chaque fois qu’un flux est redémarré, la politique de protection doit être à nouveau définie sur le flux. La procédure est décrite à l’étape 5-d.
pMFOutputTrustAuthority->Release() pMFTrustedOutput->Release()
Les exemples de code suivants montrent une implémentation d’exemple des objets de politique et de schéma.
//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 \