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

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

  • Comments 1

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.

Source and binaries (x86 and amd64) attached.

>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
);

 

Attachment: trustedaudiodrivers2.zip
Leave a Comment
  • Please add 8 and 8 and type the answer here:
  • Post
  • Some common errors and what they mean:

    -- ERROR -- IMFTrustedOutput::GetOutputTrustAuthority(0) failed: hr = 0x80070057

    That's E_INVALIDARG, there.  That usually means that the audio device wasn't playing anything at the time the GetOutputTrustAuthority call was made.  Double-check that you're playing audio, and over the right device.  WMP's "repeat" feature is very handy here.  You can also configure WMP to play over a specific audio device rather than the default.

    -- ERROR -- IMFOutputTrustAuthority::SetPolicy failed: hr = 0x80000071

    That's a DRM authentication failure.  Either there's a kernel debugger attached, or driver verifier is turned on, or a driver binary doesn't match its signature in its .cat file, or the .cat file doesn't have a DRMLevel signature, or the DRMLevel you asked for in the output policy (1300, say) exceeds the DRMLevel that the .cat file is signed for (1200, say), or the driver is test-signed and your output policy doesn't allow for test-signed drivers.  Double-check the .cat file against the output policy you're requesting.

    -- ERROR -- IMFOutputTrustAuthority::SetPolicy failed: hr = 0xc00000bb

    That's a status code coming from the driver - in particular, this is STATUS_NOT_SUPPORTED.  This usually means that you asked for CopyOK to be 0 and DigitalOutputDisable to be 0, but the driver or device doesn't support HDCP or turning on the status bits.  For an HDMI device, look in the Sound control panel on the Supported Formats tab for the device in question and see if "HDCP: Supported" is set.

Page 1 of 1 (1 items)