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); } } }
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; }
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)); } }); }
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>()); } }
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); }
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()); }
public void OnDRMInitDataFound(DRMInitData data) { if (!streams.ContainsKey(data.StreamType)) { return; } streams[data.StreamType].OnDRMFound(data); }
private static DRMInitData CreateWidevineDrmInitData() { var drmInitData = new DRMInitData() { InitData = initWidevineData, SystemId = WidevineSystemId, StreamType = StreamType.Video, }; return(drmInitData); }
private static DRMInitData CreatePlayReadyDrmInitData() { var drmInitData = new DRMInitData() { InitData = initPlayReadyData, SystemId = PlayreadySystemId, StreamType = StreamType.Video, }; return(drmInitData); }
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)); }
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)); } }
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); } } }