Matthew van Eerde's web log

  • Matthew van Eerde's web log

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

    • 1 Comments

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

     

  • Matthew van Eerde's web log

    Rules for making change

    • 0 Comments

    It happens a million times a day.  Somebody pays cash for something and gets change.  But there are rules, and Raymond's friend seems to like to break those rules.  Luckily for Raymond's friend, one of the rules is the customer is always right... or as Mr. Krabs would say, the money is always right.  This blog post is about a couple of the more mathematical rules.

    Rule for the cashier: you must give "canonical" change.

    Whether to honor requests for non-canonical change is a complicated morass I will not attempt to tackle in this blog post as too much depends on context.  But the initial offering must be canonical.

    By "canonical change", I mean the cashier must give change using the smallest possible number of canonical coins and bills.  For example, (one quarter + one nickel) is a rendering of $0.30 using only two coins, while (three dimes) is three coins, so a cashier must never give change that includes three dimes.

    By "canonical coins and bills" I mean (in the U.S.) this precise list:

    • penny
    • nickel
    • dime
    • quarter
    • $1 bill
    • $5 bill
    • $10 bill
    • $20 bill
    I discuss usage of non-canonical (unusual) coins and bills later.

    Rule 1 for the customer: "Tap, tap, no takebacks"

    The tender and canonical change cannot intersect.

    Don't give the cashier anything they would just hand back to you directly.

    This is the rule that Raymond's friend broke - it just wastes everyone's time to play musical chairs with the money.
    Actually, this rule is just a corollary of the more general rule:

    Rule 2 for the customer: "No side transactions."

    No subset of the tender can have the same value as any subset of canonical change for that tender.

    Don't give the cashier anything that they would just hand back to you in coalesced form.

    If you want to consolidate your change, go to a bank or use one of those big machines.

    Corollary 1: it is always OK to pay with a single large bill.
    Corollary 2: it is always OK to give exact change.

    Unusual denominations:

    The two-dollar bill, the dollar coin (in any of its forms), the half-dollar coin, and bills higher than $20 are "unusual" denominations that complicate the situation slightly.

    Rule for the cashier: Unusual denominations stay in the drawer.

    Accept them (unless there are security rules at your place of business) but they are explicitly not part of any canonical change.

    Rule for the customer: Go right ahead.

    You can pay with an unusual denomination provided that you do not break the "no side transactions" rule or any large-denomination security rule at the business in question.

    Examples:

    In the following examples, "total" is the amount owed; "tender" is the amount the customer gives to the cashier; and "change" is what the cashier gives back to the customer.

    Total Tender Change Notes
    $5.20 $5 bill + $2 bill $1 bill + three quarters + one nickel OK - cashier correctly accepted the $2
    $5.20

    $5 bill + $1 bill

    two quarters + three dimes Cashier gave out more coins than necessary
    $5.20 $5 bill + $1 bill half-dollar + one quarter + one nickel Cashier gave out non-canonical half-dollar
    $5.20 $5 bill + four quarters three quarters + one nickel Customer gave three "takeback" quarters
    $5.20 $5 bill + quarter + nickel dime OK
    $5.20 $5 bill + quarter + five pennies dime OK
    $5.20 $5 bill + quarter + ten pennies dime + nickel Customer got nickel for five pennies in "side transaction"

    In the last row, you can think of the "side transaction" as either five pennies for a nickel or ten pennies for a dime. I prefer the former.

Page 1 of 1 (2 items)

November, 2009