Test Wowza Streaming Engine MPEG-DASH WebM encryption using Shaka player

This article describes how to quickly test MPEG-DASH WebM encryption using Shaka player and an encryption key embedded in HTML code (not secure). This article assumes you're sending a WebM compatible VP8/VP9 stream directly to Wowza Streaming Engine™ media server software. (You can also use Wowza Transcoder to generate the VP8/VP9 stream.) The examples in this article use the default Wowza Streaming Engine live application and a live WebM stream named myStream.

Note: Wowza Streaming Engine 4.4.0 or later is required.
  1. Download and build Shaka player:
     
    1. Navigate to the shaka-player project repository, and then clone or download the project files.
       
    2. Build the player (using Cygwin, change directory to build, and then run build.sh).
       
    3. Copy the player to a web server.
  2. Configure the default live application in Wowza Streaming Engine for MPEG-DASH streaming. For configuration instructions, see How to do MPEG-DASH streaming.
     
  3. Add the following custom module that injects DRM information into the live stream:
     
    import com.wowza.wms.drm.cenc.*;
    import com.wowza.wms.module.*;
    import com.wowza.wms.stream.livepacketizer.*;
    
    public class ModuleWebMDashEncryption extends ModuleBase
    {
        public static class WebMDashCustomDRMInfo implements ICencDRMInfo
        {
            String systemName = null;
            String systemId = null;
            String url = null;
    
            public WebMDashCustomDRMInfo(String systemName)
            {
                this.systemName = systemName;
            }
    
            @Override
            public void setSystemId(String systemId)
            {
                this.systemId = systemId;
            }
    
            @Override
            public String getSystemId()
            {
                return systemId;
            }
    
            @Override
            public String getURL()
            {
                return url;
            }
    
            @Override
            public void setURL(String url)
            {
                this.url = url;
            }
    
            @Override
            public String getNameSpaces()
            {
                return null;
            }
    
            @Override
            public String getMPEGDashCPSubElements(boolean keyRotation)
            {
                return null;
            }
    
            @Override
            public String getSystemName()
            {
                return this.systemName;
            }
    
            @Override
            public boolean supportsKeyGeneration()
            {
                return false;
            }
    
            @Override
            public byte[] generateKey(byte[] KID)
            {
                return null;
            }
    
            @Override
            public void updateKeyInfo(byte[] KID, byte[] contentKey)
            {
            }
    
            @Override
            public byte[] serialize()
            {
                return null;
            }
    
            @Override
            public void deserialize(byte[] data)
            {
            }
    
            @Override
            public byte[] getPsshData(boolean keyRotation)
            {
                return null;
            }
    
            @Override
            public void setPsshData(byte[] psshData)
            {
            }
    
            @Override
            public boolean isComplete()
            {
                return true;
            }
        }
    
        public void onHTTPMPEGDashEncryptionKeyLiveChunk(ILiveStreamPacketizer liveStreamPacketizer, String streamName, CencInfo cencInfo, long chunkId)
        {
            if (cencInfo.getKID() != null && cencInfo.getEncKeyString() != null)
            {
                try
                {
                    String idStr = "test";
                    String url = "empty";
                    String systemId = "12345678-1234-1234-1234-123456789012";
    
                    WebMDashCustomDRMInfo drmInfo = new WebMDashCustomDRMInfo(idStr);
    
                    drmInfo.setURL(url);
                    drmInfo.setSystemId(systemId);
    
                    getLogger().info("ModuleWebMDashEncryption.onHTTPMPEGDashEncryptionKeyLiveChunk["+streamName+"]: Add DRM: "+idStr+":"+systemId);
                    cencInfo.addDRM(idStr+":"+systemId, drmInfo);
                    cencInfo.setKeyRotationType(CencInfo.KEY_ROTATION_TYPE_NONE);
                    cencInfo.setPSSHVersion(CencInfo.PSSH_VERSION_1);
                }
                catch (Exception e)
                {
                    getLogger().error("ModuleWebMDashEncryption.onHTTPMPEGDashEncryptionKeyLiveChunk["+streamName+"]: ", e);
                }
            }
        }
    }
  4. Add a key file named [install-dir]/keys/myStream.key to encrypt the live stream.
     
    mpegdashstreaming-cenc-key-id: 12345DCF-7F93-4B8E-85C7-F908840DA059
    mpegdashstreaming-cenc-content-key: Hh8gISIjJCUmJx4fICEiIw==
    mpegdashstreaming-cenc-algorithm: AESCTR
    mpegdashstreaming-cenc-pssh-version: 1
  5. Modify Shaka player to inject the key into the player: Edit appUtils.js and add the following if statement to the appUtils.interpretContentProtection function near the top of the function.
     
    if (schemeIdUri == "urn:uuid:12345678-1234-1234-1234-123456789012") {
    
    var keyid = Uint8ArrayUtils.fromBase64('EjRdz3+TS46Fx/kIhA2gWQ'); // 12345DCF-7F93-4B8E-85C7-F908840DA059
    var key = Uint8ArrayUtils.fromBase64('Hh8gISIjJCUmJx4fICEiIw');
    
    var keyObj = {
    kty: 'oct',
    alg: 'A128KW',
    kid: Uint8ArrayUtils.toBase64(keyid, false),
    k: Uint8ArrayUtils.toBase64(key, false)
    };
    
    var jwkSet = {keys: [keyObj]};
    license = JSON.stringify(jwkSet);
    
    console.log("license:"+license);
    console.log("keyid:"+keyid);
    console.log("key:"+key);
    
    var initData = {
    'initData': keyid,
    'initDataType': 'webm'
    };
    
    var licenseServerUrl = 'data:application/json;base64,' + window.btoa(license);
    
    return [{
    'keySystem': 'org.w3.clearkey',
    'licenseServerUrl': licenseServerUrl,
    'initData': initData
    }];
    }
  6. Send a WebM-compatible live stream named myStream to the live application in Wowza Streaming Engine.

You should see a log statement similar to the following that indicates the stream is being encrypted.

MPEGDashWriterHandler.createChunkWebM[live/_definst_/myStream]: WebM encryption: kid:12345dcf7f934b8e85c7f908840da059
  1. Play the stream using your modified Shaka player.

The stream should play properly.