How to turn on HDCP or SCMS in an audio playback app

There’s an MSDN sample of how to turn on HDCP or SCMS in a playback app.  The sample is loosely based on a test app I wrote, but there are still some rough edges.  For example, the CMFAttributeImpl<T> template is not part of the SDK or the DDK.  Also, there’s a leak in the GetDigitalAudioEndpoint implementation.  (Using the private template was my bug.  The leak was someone else’s.)

Exercise: find the leak.

There are also rough edges in the test app.  For one thing, it doesn’t play audio – the way to use the app is to

  1. Start playing audio using your favorite audio playback application, to the digital output on which want to turn on HDCP or SCMS.
  2. Run the trustedaudiodrivers2.exe command line to do what you want it to.

Browse source

Download trustedaudiodrivers2.exe

>trustedaudiodrivers2
trustedaudiodrivers2 --list-devices

trustedaudiodrivers2
    --device [ communications | console | multimedia | <device-name>]
    --copy-ok [ 0 | 1 ]
    --digital-output-disable [ 0 | 1 ]
    --test-certificate-enable [ 0 | 1 ]
    --drm-level <drm-level>

--list-devices: displays a list of output devices.

Sets a Trusted Audio Drivers 2 output policy on a given audio endpoint.
--device
    communications: set policy on default communications render endpoint.
    console: set policy on default console render endpoint.
    multimedia: set policy on default multimedia render endpoint.
    <device-name>: set policy on the endpoint with this long name.
--copy-ok: 1 or 0. Set to 0 to turn on "copy protection" (SCMS or HDCP)
--digital-output-disable: 1 or 0. Set to 1 to disable output (or turn on HDCP.) --test-certificate-enable: 1 or 0. Set to 1 to allow the test certificate.
--drm-level: set to a number. 1100 is a good default.

Here’s a sample command line which should disable the digital out (or enable HDCP, if the driver supports it.)  This is line-wrapped for readability only.

>trustedaudiodrivers2.exe
    --device "Acer H213H (High Definition Audio Device)"
    --copy-ok 1
    --digital-output-disable 1
    --test-certificate-enable 1
    --drm-level 1300

If all goes well the output should look something like this:

Output Trust Authorities on this endpoint: 2
Processing Output Trust Authority #1 of 2
OTA action is PEACTION_PLAY (1)
GetOriginatorID() called
GetOriginatorID() called
GenerateRequiredSchemas() called
dwAttributes: MFOUTPUTATTRIBUTE_DIGITAL (0x00000001)
guidOutputSubType: MFCONNECTOR_HDMI ({57CD596D-CE47-11D9-92DB-000BDB28FF98})
cProtectionSchemasSupported: 1
MFPROTECTION_TRUSTEDAUDIODRIVERS ({65BDF3D2-0168-4816-A533-55D47B027101})
MFPROTECTION_TRUSTEDAUDIODRIVERS supported.
IMFOutputSchema::GetSchemaType called
IMFOutputSchema::GetConfigurationData called
IMFOutputTrustAuthority::SetPolicy returned 0x00000000
Processing Output Trust Authority #2 of 2
OTA action is PEACTION_EXTRACT (4)
Skipping as the OTA action is not PEACTION_PLAY
Policy successfully applied.  Press any key to release IMFTrustedOutput...

At that point I pressed a key, which redacted the policy, and the music started playing again.

Common causes of failures:

  1. No audio is playing to that device.  Setting protection requires an active audio stream.
  2. The audio device is not S/PDIF or HDMI.
  3. The audio driver is not capable of enforcing the protection.
  4. The audio driver is test-signed only; try –test-certificate-enable 1
  5. Kernel debugging is enabled.
  6. Driver verifier is enabled.

This source should compile with just publically available headers and no special voodoo on the part of the developer.

EDIT: 11/13/2009 10:05 AM

A subtle problem was called to my attention.  This line triggers an ATL ASSERT:

hr = pMFOutputTrustAuthority->SetPolicy(&pMFOutputPolicy, 1, &pbTicket, &cbTicket);

The ASSERT is in CComPtr<IMFOutputPolicy>::operator& which ASSERTs if the pointer CComPtr<IMFOutputPolicy>::p is not NULL.

My first instinct was to bypass the assertion like this:

hr = pMFOutputTrustAuthority->SetPolicy(&pMFOutputPolicy.p, 1, &pbTicket, &cbTicket);

But ASSERTs are there for a reason.  The fundamental problem here is that I’m trying to be too clever.

Despite its name, IMFOutputTrustAuthority::SetPolicy takes, not an IMFOutputPolicy *, but an array of IMFOutputPolicy *s.  A little confusing, yes.  As this is effectively a sample, I should be emphasizing this behavior, not covering it up.

So here’s the fix I decided on.  Updated source and binaries attached.

// we're only setting a single policy but the API allows setting multiple policies
// (like WaitForMultipleObjects)
IMFOutputPolicy *rMFOutputPolicies[1] = { pMFOutputPolicy };
hr = pMFOutputTrustAuthority->SetPolicy(
    rMFOutputPolicies,
    ARRAYSIZE(rMFOutputPolicies),
    &pbTicket,
    &cbTicket
);

EDIT September 28 2015: moved source to https://github.com/mvaneerde/blog/tree/master/trustedaudiodrivers2

One thought on “How to turn on HDCP or SCMS in an audio playback app

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s