Пример #1
0
        public IDrmSession CreateDRMSession(DRMInitData data)
        {
            Logger.Info("Create DrmSession");

            lock (drmHandlers)
            {
                var handler = drmHandlers.FirstOrDefault(o => o.SupportsSystemId(data.SystemId));
                if (handler == null)
                {
                    Logger.Warn("unknown drm init data");
                    return(null);
                }

                var scheme = handler.GetScheme(data.SystemId);

                lock (clipDrmConfiguration)
                {
                    var drmConfiguration = clipDrmConfiguration.FirstOrDefault(o => SchemeEquals(o.Scheme, scheme));
                    if (drmConfiguration == null)
                    {
                        Logger.Warn("drm not configured");
                        return(null);
                    }

                    var session = handler.CreateDRMSession(data, drmConfiguration);
                    return(session);
                }
            }
        }
Пример #2
0
        public void OnDRMFound(DRMInitData data)
        {
            Logger.Info($"{streamType}");

            if (!forceDrmChange && drmSession != null)
            {
                return;
            }

            IDrmSession newSession = drmManager.CreateDRMSession(data);

            // Do not reset wait for DRM event. If there is no valid session
            // do not want to append new data
            //
            if (newSession == null)
            {
                return;
            }

            Logger.Info($"{streamType}: New DRM session found");
            forceDrmChange = false;

            // Decrement use counter for packet stream on old DRM Session
            drmSession?.Release();

            // Add reference count for new session
            newSession.Share();

            // Set new session as current & let data submitters run wild.
            // There is no need to store sessions. They live in player queue
            drmSession = newSession;
        }
Пример #3
0
        public void Start_DRMInitDataFound_PublishesDRMInitData(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var initData = new DRMInitData
                {
                    StreamType = StreamType.Video,
                    InitData   = new byte[1]
                };
                var demuxerStub = CreateDemuxerStub(new ClipConfiguration
                {
                    DrmInitDatas = new List <DRMInitData> {
                        initData
                    }
                }, startType);

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var initDataTask = controller.DrmInitDataFound().FirstAsync().ToTask();

                    StartController(controller, startType);

                    var receivedInitData = await initDataTask;
                    Assert.That(receivedInitData, Is.EqualTo(initData));
                }
            });
        }
Пример #4
0
        public void OnAppendPacket_WhenDrmSessionIsConfigured_CallsPlayerAdapter()
        {
            var codecExtraDataHandlerStub = Substitute.For <ICodecExtraDataHandler>();

            var drmSessionStub = CreateDrmSessionFake();

            var drmManagerStub = CreateDrmManagerFake(drmSessionStub);

            var playerMock = Substitute.For <IPlayer>();

            using (var stream = CreatePacketStream(StreamType.Audio, playerMock, drmManagerStub, codecExtraDataHandlerStub))
            {
                var packet = new EncryptedPacket()
                {
                    StreamType = StreamType.Audio
                };
                var config      = new AudioStreamConfig();
                var drmInitData = new DRMInitData();

                stream.OnStreamConfigChanged(config);
                stream.OnDRMFound(drmInitData);
                stream.OnAppendPacket(packet);

                playerMock.Received().AppendPacket(Arg.Any <Packet>());
            }
        }
Пример #5
0
        private void ParseCencScheme(ContentProtection descriptor, string schemeIdUri)
        {
            var doc = new XmlDocument();

            try
            {
                doc.LoadXml(descriptor.Data);
            }
            catch (Exception)
            {
                return;
            }

            // read first node inner text (should be psshbox or pro header)
            var initData = doc.FirstChild?.FirstChild?.InnerText;

            if (initData == null)
            {
                return;
            }

            var drmInitData = new DRMInitData
            {
                KeyIDs   = CencUtils.GetKeyIDs(descriptor.CencDefaultKID),
                DataType = CencUtils.GetInitDataType(doc.FirstChild?.FirstChild?.Name),
                InitData = Convert.FromBase64String(initData),
                SystemId = CencUtils.SchemeIdUriToSystemId(schemeIdUri),
                // Stream Type will be appended during OnDRMInitDataFound()
            };

            drmInitDataSubject.OnNext(drmInitData);
        }
Пример #6
0
        public static List <byte[]> GetKeyIds(DRMInitData initData)
        {
            var mpdSource = initData.KeyIDs?.Select(UuidToKey) ?? Enumerable.Empty <byte[]>();

            IEnumerable <byte[]> initDataSource;

            try
            {
                switch (initData.DataType)
                {
                case DRMInitDataType.MsPrPro:
                    Logger.Info(initData.DataType.ToString());
                    initDataSource = MicrosoftPlayReadyObjectHeader(initData.InitData);
                    break;

                case DRMInitDataType.Pssh:
                    Logger.Info(initData.DataType.ToString());
                    initDataSource = PsshBox(initData.InitData);
                    break;

                default:
                    initDataSource = Enumerable.Empty <byte[]>();
                    break;
                }
            }
            catch (IndexOutOfRangeException)
            {
                // Init data seems malformed. May still usable by underlying decryption mechanisms.
                // Try processing what's available
                Logger.Warn("Possibly malformed DRMInitData.initData");
                initDataSource = Enumerable.Empty <byte[]>();
            }

            return(mpdSource.Concat(initDataSource).ToList());
        }
Пример #7
0
        public void OnDRMInitDataFound(DRMInitData data)
        {
            if (!streams.ContainsKey(data.StreamType))
            {
                return;
            }

            streams[data.StreamType].OnDRMFound(data);
        }
Пример #8
0
        private static DRMInitData CreateWidevineDrmInitData()
        {
            var drmInitData = new DRMInitData()
            {
                InitData   = initWidevineData,
                SystemId   = WidevineSystemId,
                StreamType = StreamType.Video,
            };

            return(drmInitData);
        }
Пример #9
0
        private static DRMInitData CreatePlayReadyDrmInitData()
        {
            var drmInitData = new DRMInitData()
            {
                InitData   = initPlayReadyData,
                SystemId   = PlayreadySystemId,
                StreamType = StreamType.Video,
            };

            return(drmInitData);
        }
Пример #10
0
        public IDrmSession CreateDRMSession(DRMInitData initData, DRMDescription drmDescription)
        {
            var iemeKeySystemName = CencUtils.GetKeySystemName(initData.SystemId);

            if (IEME.isKeySystemSupported(iemeKeySystemName) != Status.kSupported)
            {
                Logger.Warn($"Key System: {iemeKeySystemName} is not supported");
                return(null);
            }
            return(CencSession.Create(initData, drmDescription));
        }
Пример #11
0
        public async Task Init_DrmInitDataAvailable_ReturnsDrmInitData(InitType initType)
        {
            var expectedData = new DRMInitData
            {
                StreamType = StreamType.Video,
                InitData   = new byte[] { 1 },
                SystemId   = new byte[] { 2 }
            };
            var formatContextStub = Substitute.For <IAVFormatContext>();

            formatContextStub.DRMInitData.Returns(new[] { expectedData });

            var glueStub = Substitute.For <IFFmpegGlue>();

            glueStub.AllocFormatContext().Returns(formatContextStub);

            using (var demuxer = CreateFFmpegDemuxer(glueStub))
            {
                var clipConfig = await InitDemuxer(demuxer, initType);

                var receivedData = clipConfig.DrmInitDatas[0];
                Assert.That(receivedData, Is.EqualTo(expectedData));
            }
        }
Пример #12
0
        public IDrmSession CreateDRMSession(DRMInitData data)
        {
            Logger.Info("Create DrmSession");

            // Before diving into locks, decode DRM InitData KeyIDs
            var keyIds        = DrmInitDataTools.GetKeyIds(data);
            var useGenericKey = keyIds.Count == 0;

            if (useGenericKey)
            {
                Logger.Info("No keys found. Using entire DRMInitData.InitData as generic key");
                keyIds.Add(data.InitData);
            }
            else
            {
                // Early exit scenario - already cached
                if (_sessionCache.TryGetSession(keyIds, out IDrmSession session))
                {
                    Logger.Info("Cached session found");
                    return(session);
                }
            }

            lock (drmHandlers)
            {
                var handler = drmHandlers.FirstOrDefault(o => o.SupportsSystemId(data.SystemId));
                if (handler == null)
                {
                    Logger.Warn("unknown drm init data");
                    return(null);
                }

                var scheme = handler.GetScheme(data.SystemId);

                lock (clipDrmConfiguration)
                {
                    var drmConfiguration = clipDrmConfiguration.FirstOrDefault(o => SchemeEquals(o.Scheme, scheme));
                    if (drmConfiguration == null)
                    {
                        Logger.Warn("drm not configured");
                        return(null);
                    }

                    // Recheck needs to be done for cached session.
                    // Early check may produce false negatives - session being created by other stream
                    // but not yet cached.
                    if (_sessionCache.TryGetSession(keyIds, out IDrmSession session))
                    {
                        Logger.Info("Cached session found");
                        return(session);
                    }

                    Logger.Info("No cached session found");

                    session = handler.CreateDRMSession(data, drmConfiguration);
                    session.Share();
                    if (_sessionCache.TryAddSession(keyIds, session))
                    {
                        return(session);
                    }

                    Logger.Info("Failed to cache session");
                    session.Release();

                    return(session);
                }
            }
        }