+#!/usr/bin/env python3
+#
+# playready_experiment.py - Example of SmoothStreaming PlayReady authentication
+#
+# Copyright (C) 2016 Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+# Experiment on how to use the ProtectionHeader element in SmoothSTreaming
+# manifest files.
+#
+# The code is just a demonstration of how to decode the ProtectionHeader element
+# content, it is not supposed to do nothing actually useful.
+#
+# Based on the PlayReady Header Object specification:
+# http://download.microsoft.com/download/1/4/7/1475C862-6B67-44B2-AF31-ABC83EA68292/PlayReady%20Header%20Object%20(7-2-2012).docx
+
+import base64
+import struct
+import sys
+import xml.etree.ElementTree as etree
+
+from pysimplesoap.client import SoapClient
+from pysimplesoap.simplexml import SimpleXMLElement
+
+
+def get_right_management_header(protection_header_text):
+ play_ready_header_objects = base64.b64decode(protection_header_text)
+
+ offset = 0
+
+ field_size = 4
+ total_size = struct.unpack("<L", play_ready_header_objects[offset:offset + field_size])[0]
+ offset += field_size
+
+ if total_size != len(play_ready_header_objects):
+ sys.stderr.write("Error, unexpected size.\n")
+ sys.exit(1)
+
+ field_size = 2
+ count = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+ offset += field_size
+
+ for i in range(count):
+ field_size = 2
+ record_type = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+ offset += field_size
+
+ field_size = 2
+ record_length = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+ offset += field_size
+
+ if record_type == 1:
+ right_management_header = play_ready_header_objects[offset:offset + record_length].decode("UTF-16")
+ return right_management_header
+ else:
+ sys.stderr.write("Error, unsupported record type. Skipping.\n")
+ offset += record_length
+
+
+def main():
+ if len(sys.argv) != 2:
+ sys.stderr.write("usage: %s <manifest>\n" % sys.argv[0])
+ sys.exit(1)
+
+ manifest_filename = sys.argv[1]
+
+ manifest = etree.parse(manifest_filename)
+ protection_header = manifest.find(".//Protection/ProtectionHeader")
+
+ challenge = get_right_management_header(protection_header.text)
+
+ challenge_xml = etree.fromstring(challenge)
+ la_url = challenge_xml.find(".//{http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader}LA_URL").text
+
+ client = SoapClient(
+ location=la_url,
+ action='http://schemas.microsoft.com/DRM/2007/03/protocols/',
+ soap_ns='soap', trace=True, ns=False)
+
+ params = SimpleXMLElement("""<AcquireLicense xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols"><challenge>""" +
+ challenge +
+ """</challenge></AcquireLicense>""")
+
+ response = client.call('AcquireLicense', params)
+ print(response)
+
+if __name__ == "__main__":
+ main()