Freigeben über


Geschütztes Benutzermodusaudio (PUMA)

Windows Vista hat den geschützten Benutzermodus Audio (PUMA) eingeführt, die Benutzermodus-Audio-Engine in der geschützten Umgebung (PE), die eine sicherere Umgebung für die Audioverarbeitung und das Rendering bietet. Dadurch können nur die akzeptablen Audioausgaben aktiviert werden, und es wird sichergestellt, dass die Ausgaben zuverlässig deaktiviert werden. Weitere Informationen zu PUMA finden Sie unter Ausgabeinhaltsschutz und Windows Vista.

PUMA wurde für Windows 7 aktualisiert, um die folgenden Features bereitzustellen:

  • Festlegen von SCMS-Bits (Serial Copy Management System) auf S/PDIF-Endpunkten und HDCP-Bits (Digital Content Protection) mit hoher Bandbreite auf High-Definition Multimedia Interface (HDMI)-Endpunkten.
  • Aktivieren von SCMS- und HDMI-Schutzsteuerungen außerhalb einer geschützten Umgebung (Protected Environment, PE).

DRM-Schutz in Audiotreibern

Digital Rights Management (DRM) bietet die Möglichkeit, Mediendaten in einem sicheren Container zu packen und Nutzungsregeln an den Inhalt anzufügen. Beispielsweise kann der Inhaltsanbieter den Kopierschutz oder die Digitale Ausgabe deaktivieren , um direkte digitale Kopien oder die Übertragung aus dem PC-System zu deaktivieren.

Der Audiostapel in bestimmten Microsoft-Produkten unterstützt DRM, indem die Nutzungsregeln implementiert werden, die die Wiedergabe der Audioinhalte steuern. Um den geschützten Inhalt wiederzugeben, muss der zugrunde liegende Audiotreiber ein vertrauenswürdiger Treiber sein. Das heißt, der Treiber muss für DRMLevel 1300 logo-zertifiziert sein. Informationen zum Entwickeln vertrauenswürdiger Treiber finden Sie unter Verwendung von Schnittstellen, die im Windows 2000 Driver Development Kit (DDK) oder höher definiert sind. Treiber, die mit dem DDK entwickelt wurden, implementieren die notwendigen Schnittstellen zu DRM. Weitere Informationen finden Sie unter Digital Rights Management.

Um den geschützten Inhalt zu rendern, muss der vertrauenswürdige Treiber überprüfen, ob Kopierschutz und Digitale Ausgabe deaktivieren für den Inhalt festgelegt sind, der durch den Audiostapel fließt, und auf die Einstellungen entsprechend reagieren.

Kopierschutzregel

Der Kopierschutz gibt an, dass direkte digitale Kopien auf dem System nicht zulässig sind. Anhang B der WHQL-Testvereinbarung wurde aktualisiert, um die neuen Erwartungen und Anforderungen eines Treibers widerzuspiegeln, wenn der Kopierschutz für den Inhalt festgelegt ist. Für Windows 7 erfüllt der integrierte HD-Audioklassentreiber die neuesten Anforderungen.

Zusätzlich zur Sicherstellung, dass Inhalte nicht an eine andere Komponente übergeben oder auf einem nicht flüchtigen Speichermedium gespeichert werden dürfen, das nicht vom DRM-System authentifiziert wird, führt der Audiotreiber beim Festlegen des Kopierschutzes die folgenden Aufgaben aus:

  • Der Treiber aktiviert HDCP auf HDMI-Endpunkten.
  • Für S/PDIF-Schnittstellen überprüft der Treiber, ob die Kombination aus L-, Cp- und Category Code-Bits den SCMS-Zustand "Copy Never" (Nie kopieren) angibt, wie in IEC 60958 definiert.
  • Das L-Bit ist auf 0 und der Kategoriecode auf "Digital Signal Mixer" festgelegt.

Die DRMRIGHTS-Struktur , die von vertrauenswürdigen Audiotreibern verwendet wird, gibt die DRM-Inhaltsberechtigungen an, die einem KS-Audio-Pin oder einem Streamobjekt des Portklassentreibers zugewiesen sind. Das CopyProtect-Element gibt an, ob der Kopierschutz für den Audioinhalt festgelegt ist.

Für Windows 7 ist die Verwendung von CopyProtect strenger. Der Treiber stellt sicher, dass die Schutzsteuerelemente auf den Audioschnittstellen festgelegt sind, HDCP für die HDMI-Ausgabe und SCMS für die S/PDIF-Ausgabe festgelegt wird, indem der Zustand auf "Nie kopieren" festgelegt wird.

Regel zum Deaktivieren der digitalen Ausgabe

Digital Output Disable gibt an, dass der Inhalt nicht aus dem System übertragen werden darf. In Windows 7 reagiert der integrierte HD-Audioklassentreiber auf diese Einstellung, indem er HDCP auf HDMI-Endpunkten aktiviert. Dies ähnelt der Antwort des Treibers auf die Kopierschutzeinstellung .

Aktivieren von Mechanismen zum Schutz von Inhalten außerhalb einer geschützten Umgebung

PUMA befindet sich in einem separaten Prozess in der Geschützten Umwelt (PE). In Windows Vista muss sich eine Medienanwendung in einem PE befinden, um die von PUMA angebotenen Steuerelemente für den Schutz von Audioinhalten verwenden zu können. Da nur Media Foundation-APIs mit einem PE interagieren können, sind die Inhaltsschutzsteuerelemente auf Anwendungen beschränkt, die Media Foundation-APIs zum Streamen von Audioinhalten verwenden.

In Windows 7 kann jede Anwendung auf die von der PUMA Output Trust Authority (OTA) bereitgestellten Inhaltsschutzkontrollen zugreifen, unabhängig davon, ob sie sich in einem PE befinden oder Media Foundation-APIs für die Audiowiedergabe verwenden.

Implementierungsanweisungen

Die folgenden Schritte sind erforderlich, damit eine Audioanwendung SCMS- oder HDCP-Inhaltsschutz auf einem Audioendpunkt steuert. Unterstützte Audio-APIs sind DirectShow, DirectSound und WASAPI.

In diesem Beispielcode werden die folgenden Schnittstellen verwendet.

Die Medienanwendung muss die folgenden Aufgaben ausführen.

  1. Einrichten der Entwicklungsumgebung

    • Verweisen Sie auf die erforderlichen Schnittstellen, und schließen Sie die im folgenden Code gezeigten Header ein.

      #include <MMdeviceapi.h>        // Device endpoint definitions
      #include <Mfidl.h>              // OTA interface definitions
      
    • Link zur Mfuuid.lib, um die OTA-Schnittstellen zu verwenden.

    • Deaktivieren Sie den Kerneldebugger und die Treiberüberprüfung, um Fehler bei der Authentifizierungsüberprüfung zu vermeiden.

  2. Enumerieren Sie alle Endpunkte im System, und wählen Sie den Zielendpunkt aus der Endpunktsammlung aus, wie im folgenden Code gezeigt. Weitere Informationen zum Aufzählen von Geräten finden Sie unter Aufzählen von Audiogeräten.

    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);
    }
    
  3. Verwenden Sie den IMMDevice-Zeiger auf den Endpunkt, der vom Enumerationsprozess zurückgegeben wird, um die gewünschte Audiostreaming-API zu aktivieren und sich auf das Streaming vorzubereiten. Unterschiedliche Audio-APIs erfordern etwas unterschiedliche Vorbereitungen.

    • Für DShow-Audioanwendungen:
      1. Erstellen Sie ein DirectShow-COM-Objekt, indem Sie IMMDevice::Activate aufrufen und IID_IBaseFilter als Schnittstellenbezeichner angeben.

        IUnknown *pDShowFilter = NULL;
        ...
        hr = pDevice->Activate (
                          IID_IBaseFilter,
                          CLSCTX_INPROC_SERVER, NULL,
                          reinterpret_cast<void **>(&pDShowFilter));
        
      2. Erstellen Sie ein DirectShow-Filterdiagramm mit diesem COM-Objekt, das vom Gerät aktiviert wird. Weitere Informationen zu diesem Prozess finden Sie unter "Erstellen des Filtergraphen" in der DirectShow SDK-Dokumentation.

    • Für DSound-Audioanwendungen:
      1. Erstellen Sie ein DSound COM-Objekt, indem Sie IMMDevice::Activate aufrufen und IID_IDirectSound8 als Schnittstellenbezeichner angeben.

        IDirectSound8  *pDSSound8;
        ...
        hr = pDevice->Activate (
                          IID_IDirectSound8,
                          CLSCTX_INPROC_SERVER, NULL,
                          reinterpret_cast<void **>(&pDSSound8));
        
      2. Verwenden Sie das oben erstellte DSound-Objekt, um DSound für das Dampfen zu programmieren. Weitere Informationen zu diesem Prozess finden Sie unter DirectSound auf MSDN.

    • Für WASAPI:
      1. Erstellen Sie ein IAudioClient-COM-Objekt , indem Sie IMMDevice::Activate aufrufen und IID_IAudioClient als Schnittstellenbezeichner angeben.

        IAudioClient *pIAudioClient = NULL;
        ...
        hr = pDevice->Activate (
                          IID_IAudioClient,
                          CLSCTX_INPROC_SERVER, NULL,
                          reinterpret_cast<void **>(&pIAudioClient));
        
      2. Öffnen Sie den Audiostream.

        hr = pIAudioClient->Initialize(...);
        
  4. Starten Sie das Audiostreaming.

  5. Legen Sie die Schutzrichtlinie für den Stream fest.

    1. Rufen Sie für WASAPI-Clients einen Verweis auf die IMFTrustedOutput-Schnittstelle des OTA-Objekts (Output Trust Authority) für den Stream ab, indem Sie IAudioClient::GetService aufrufen und IID_IMFTrustedOutput als Schnittstellenbezeichner angeben.

      IMFTrustedOutput*       pTrustedOutput = NULL;
      hr = pIAudioClient>GetService(
                     __uuidof(IMFTrustedOutput),
                     (void**)& pTrustedOutput);
      
    2. Rufen Sie die Anzahl der verfügbaren OTA-Objekte ab, indem Sie IMFTrustedOutput::GetOutputTrustAuthorityCount aufrufen.

      hr = pTrustedOutput->GetOutputTrustAuthorityCount(&m_dwCountOTA);
      
    3. Listen Sie die OTA-Auflistung auf, und rufen Sie einen Verweis auf das OTA-Objekt ab, das die Aktion PEACTION_PLAY unterstützt. Alle OTAs machen die IMFOutputTrustAuthority-Schnittstelle verfügbar.

      hr = pMFTrustedOutput->GetOutputTrustAuthorityByIndex(I, &pMFOutputTrustAuthority);
      hr = pMFOutputTrustAuthority->GetAction(&action) 
      
    4. Verwenden Sie die IMFTrustedOutput-Schnittstelle , um die Schutzrichtlinie für den Stream festzulegen.

      hr = pTrustedOutput ->SetPolicy(&pPolicy, nPolicy, &pbTicket, &cbTicket);
      

      Hinweis

      Wenn Sie EVR verwenden, löst SetPolicy das MEPolicySet-Ereignis aus und gibt MF_S_WAIT_FOR_POLICY_SET zurück, um anzugeben, dass die OTA die Richtlinie asynchron erzwingt. In diesem Beispielcode ist die Anwendung jedoch ein direkter WASAPI-Client, der das OTA-Objekt vom Audioclient abgerufen hat (Schritt 5 a). Im Gegensatz zum EVR implementieren ein Audioclient und andere WASAPI-Objekte keine Medienereignisgeneratoren. Ohne Medienereignisgeneratoren gibt IMFTrustedOutput::SetPolicy keine MF_S_WAIT_FOR_POLICY_SET zurück.

      Die Audiorichtlinieneinstellungen müssen nach dem Starten des Audiostreamings festgelegt werden, andernfalls schlägt IMFTrustedOutput::GetOutputTrustAuthorityByIndex fehl. Außerdem muss der zugrunde liegende Audiotreiber ein vertrauenswürdiger Treiber sein, um dieses Feature zu unterstützen.

       

      Im Beispielcode ist pPolicy ein Zeiger auf die IMFOutputPolicy-Schnittstelle eines vom Client implementierten Richtlinienobjekts. Weitere Informationen finden Sie in der Dokumentation zum Media Foundation SDK .

      Bei der Implementierung der IMFOutputPolicy::GenerateRequiredSchemas-Methode muss eine Sammlung der Ausgabeschutzsysteme (Schemas) generiert werden, die von der OTA erzwungen werden muss. Jedes Schema wird durch eine GUID identifiziert und enthält Konfigurationsdaten für das Schutzsystem. Stellen Sie sicher, dass die Schutzsysteme in der Sammlung auf die Verwendung vertrauenswürdiger Audiotreiber beschränkt sind. Diese Einschränkung wird durch die GUID, MFPROTECTION_TRUSTEDAUDIODRIVERS, DISABLE oder CONSTRICTAUDIO identifiziert. Wenn MFPROTECTION_TRUSTEDAUDIODRIVERS verwendet wird, handelt es sich bei den Konfigurationsdaten für dieses Schema um ein DWORD. Weitere Informationen zu den Schemas und den zugehörigen Konfigurationsdaten finden Sie in der Dokumentation zum Sdk für geschützte Umgebungen.

      Der Client muss auch die Schemadefinition bereitstellen, indem er die IMFOutputSchema-Schnittstelle implementiert. IMFOutputSchema::GetSchemaType ruft MFPROTECTION_TRUSTEDAUDIODRIVERS als Schema-GUID ab. IMFOutputSchema::GetConfigurationData gibt einen Zeiger auf die Konfigurationsdaten des Schemas zurück.

  6. Setzen Sie das Audiostreaming fort.

  7. Stellen Sie sicher, dass die Schutzrichtlinie klar ist, bevor Sie das Streaming beenden.

    Geben Sie die oben genannten Verweise auf die zugehörige Richtlinienschnittstelle frei.

    Die Releaseaufrufe löschen die zuvor festgelegten Richtlinieneinstellungen.

    Hinweis

    Jedes Mal, wenn ein Stream neu gestartet wird, muss die Schutzrichtlinie für den Stream erneut festgelegt werden. Das Verfahren wird in Schritt 5-d beschrieben.

    pMFOutputTrustAuthority->Release()
    pMFTrustedOutput->Release()
    

Die folgenden Codebeispiele zeigen eine Beispielimplementierung der Richtlinien- und Schemaobjekte.

//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 \

Programmierhandbuch

Audiokomponenten im Benutzermodus