/// <summary> /// Beginnt mit dem Auslesen der Quelldaten. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <param name="device">Das zu verwendende Gerät.</param> /// <param name="profile">Optional das zu berücksichtigende Geräteprofil.</param> /// <returns>Die Hintergrundaufgabe zum Auslesen der Quelledaten.</returns> public static CancellableTask <SourceInformation> GetSourceInformationAsync(this Hardware device, SourceIdentifier source, Profile profile = null) { // Validate if (device == null) { throw new ArgumentNullException("no hardware to use", "device"); } if (source == null) { throw new ArgumentException("no source to get information for", "source"); } // Attach to tasks var patReader = device.AssociationTableReader; var groupReader = device.GroupReader; // Start return (CancellableTask <SourceInformation> .Run(cancel => { // Check tasks if (groupReader == null) { return null; } if (patReader == null) { return null; } // Wait on tasks if (!groupReader.CancellableWait(cancel)) { return null; } if (!patReader.CancellableWait(cancel)) { return null; } // Get the current group information var groupInfo = groupReader.Result; if (groupInfo == null) { return null; } // See if group exists if (!groupInfo.Sources.Any(source.Equals)) { return null; } // Find the stream identifier for the service var pmtIdentifier = patReader.Result.FindService(source.Service); if (!pmtIdentifier.HasValue) { return null; } // Wait for mapping table var pmtReader = device.GetTableAsync <PMT>(pmtIdentifier.Value); if (!pmtReader.CancellableWait(cancel)) { return null; } // Request table var pmts = pmtReader.Result; if (pmts == null) { return null; } // Create dummy var currentSettings = new SourceInformation { Source = source, VideoType = VideoTypes.NoVideo }; // Process all PMT - actually should be only one foreach (var pmt in pmts) { // Overwrite encryption if CA descriptor is present if (pmt.Table.Descriptors != null) { currentSettings.IsEncrypted = pmt.Table.Descriptors.Any(descriptor => EPG.DescriptorTags.CA == descriptor.Tag); } // Process the program entries foreach (var program in pmt.Table.ProgramEntries) { currentSettings.Update(program); } } // Find the related station information var station = groupInfo.Sources.FirstOrDefault(source.Equals) as Station; if (station != null) { // Take data from there currentSettings.Provider = station.Provider; currentSettings.Name = station.Name; // See if this is a service currentSettings.IsService = station.IsService; // Overwrite encryption if regular service entry exists if (!currentSettings.IsService) { currentSettings.IsEncrypted = station.IsEncrypted; } } // See if profile is attached if (profile != null) { // Apply the modifier var modifier = profile.GetFilter(currentSettings.Source); if (modifier != null) { modifier.ApplyTo(currentSettings); } } // Report return currentSettings; })); }
/// <summary> /// Beginnt mit dem Auslesen der Quelldaten. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <param name="device">Das zu verwendende Gerät.</param> /// <param name="profile">Optional das zu berücksichtigende Geräteprofil.</param> /// <returns>Die Hintergrundaufgabe zum Auslesen der Quelledaten.</returns> public static CancellableTask<SourceInformation> GetSourceInformationAsync( this Hardware device, SourceIdentifier source, Profile profile = null ) { // Validate if (device == null) throw new ArgumentNullException( "no hardware to use", "device" ); if (source == null) throw new ArgumentException( "no source to get information for", "source" ); // Attach to tasks var patReader = device.AssociationTableReader; var groupReader = device.GroupReader; // Start return CancellableTask<SourceInformation>.Run( cancel => { // Check tasks if (groupReader == null) return null; if (patReader == null) return null; // Wait on tasks if (!groupReader.CancellableWait( cancel )) return null; if (!patReader.CancellableWait( cancel )) return null; // Get the current group information var groupInfo = groupReader.Result; if (groupInfo == null) return null; // See if group exists if (!groupInfo.Sources.Any( source.Equals )) return null; // Find the stream identifier for the service var pmtIdentifier = patReader.Result.FindService( source.Service ); if (!pmtIdentifier.HasValue) return null; // Wait for mapping table var pmtReader = device.GetTableAsync<PMT>( pmtIdentifier.Value ); if (!pmtReader.CancellableWait( cancel )) return null; // Request table var pmts = pmtReader.Result; if (pmts == null) return null; // Create dummy var currentSettings = new SourceInformation { Source = source, VideoType = VideoTypes.NoVideo }; // Process all PMT - actually should be only one foreach (var pmt in pmts) { // Overwrite encryption if CA descriptor is present if (pmt.Table.Descriptors != null) currentSettings.IsEncrypted = pmt.Table.Descriptors.Any( descriptor => EPG.DescriptorTags.CA == descriptor.Tag ); // Process the program entries foreach (var program in pmt.Table.ProgramEntries) currentSettings.Update( program ); } // Find the related station information var station = groupInfo.Sources.FirstOrDefault( source.Equals ) as Station; if (station != null) { // Take data from there currentSettings.Provider = station.Provider; currentSettings.Name = station.Name; // See if this is a service currentSettings.IsService = station.IsService; // Overwrite encryption if regular service entry exists if (!currentSettings.IsService) currentSettings.IsEncrypted = station.IsEncrypted; } // See if profile is attached if (profile != null) { // Apply the modifier var modifier = profile.GetFilter( currentSettings.Source ); if (modifier != null) modifier.ApplyTo( currentSettings ); } // Report return currentSettings; } ); }
/// <summary> /// Beginnt die Aufzeichnung in einen <i>Transport Stream</i> - optional als /// Datei. /// </summary> /// <param name="nextPID">Die erste Datenstromkennung (PID), die in der Aufzeichnungsdatei verwendet werden darf.</param> /// <param name="recreate">Gesetzt, wenn ein Neustart aufgrund veränderter Nutzdatenströme erforderlich wurde.</param> /// <exception cref="ArgumentException">Eine Aufzeichnung der angegebenen Quelle ist nicht möglich.</exception> private void CreateStream(short nextPID, bool recreate) { // Try to get the full name var filePath = m_OriginalPath; if (filePath != null) { if (m_FileCount > 0) { // Split off the parts var name = Path.GetFileNameWithoutExtension(filePath); var dir = Path.GetDirectoryName(filePath); var ext = Path.GetExtension(filePath); // Construct new name filePath = Path.Combine(dir, $"{name} - {m_FileCount}{ext}"); } } // Try to decrypt if (m_Decrypting = m_OriginalSettings.IsEncrypted) { try { // Process Hardware.Decrypt(Source); } catch { // Ignore any error m_Decrypting = false; } } // Type of the video EPG.StreamTypes?videoType; // Video first if (m_OriginalSettings.VideoStream == 0) { videoType = null; } else { videoType = (m_OriginalSettings.VideoType == VideoTypes.H264) ? EPG.StreamTypes.H264 : EPG.StreamTypes.Video13818; } // Get the buffer size var bufferSize = (FileBufferSizeChooser == null) ? null : FileBufferSizeChooser(videoType); // Create the new stream m_TransportStream = new Manager(filePath, nextPID, bufferSize.GetValueOrDefault(Manager.DefaultBufferSize)); // Attach PCR sink m_TransportStream.OnWritingPCR = m_WritePCRSink; // Report of the actually selected streams StreamSelection result = new StreamSelection(); // Cleanup on any error try { // Video first if (videoType.HasValue) { AddConsumer(m_OriginalSettings.VideoStream, StreamTypes.Video, m_TransportStream.AddVideo((byte)videoType.Value)); } // Select audio ProcessAudioSelection(AudioTypes.MP2, result.MP2Tracks, StreamSelection.MP2Tracks); ProcessAudioSelection(AudioTypes.AC3, result.AC3Tracks, StreamSelection.AC3Tracks); // Videotext if (StreamSelection.Videotext) { if (0 != m_OriginalSettings.TextStream) { // Register AddConsumer(m_OriginalSettings.TextStream, StreamTypes.VideoText, m_TransportStream.AddTeleText()); // Remember result.Videotext = true; } } // Subtitle streams var subtitles = new Dictionary <ushort, List <EPG.SubtitleInfo> >(); // Preset mode result.SubTitles.LanguageMode = LanguageModes.All; // All audio // Subtitles foreach (var subtitle in m_OriginalSettings.Subtitles) { // Check for primary if (StreamSelection.SubTitles.LanguageMode == LanguageModes.Primary) { // Attach to the list AddSubtitleInformation(subtitle, subtitles); // Copy over result.SubTitles.LanguageMode = LanguageModes.Primary; // Remember result.SubTitles.Languages.Add(subtitle.Language); // Done break; } // Standard selection if (StreamSelection.SubTitles.Contains(subtitle.Language)) { // Attach to the list AddSubtitleInformation(subtitle, subtitles); // Remember result.SubTitles.Languages.Add(subtitle.Language); } else { // At least one is excluded result.SubTitles.LanguageMode = LanguageModes.Selection; } } // Clear flag if no audio is used if (LanguageModes.All == result.SubTitles.LanguageMode) { if (result.SubTitles.Languages.Count < 1) { result.SubTitles.LanguageMode = LanguageModes.Selection; } } // Process all subtitles foreach (var current in subtitles) { AddConsumer(current.Key, StreamTypes.SubTitle, m_TransportStream.AddSubtitles(current.Value.ToArray())); } // See if program guide is requested bool epg = StreamSelection.ProgramGuide; // May want to disable if (epg) { if ((Hardware.Profile != null) && Hardware.Profile.DisableProgramGuide) { epg = false; } else if (Profile != null) { if (Profile.GetFilter(Source).DisableProgramGuide) { epg = false; } } } // EPG if (epg) { // Activate dispatch m_TransportStream.SetEPGMapping(Source.Network, Source.TransportStream, Source.Service); // Start it Hardware.AddProgramGuideConsumer(DispatchEPG); // Remember result.ProgramGuide = true; } // Counter int started = 0; try { // Start all foreach (var consumer in m_Consumers) { try { // Forward Hardware.SetConsumerState(consumer, true); // Count it ++started; } catch (OutOfConsumersException) { // Translate throw new OutOfConsumersException(m_Consumers.Count, started) { RequestedSelection = result }; } } } catch { // Detach EPG Hardware.RemoveProgramGuideConsumer(DispatchEPG); // Cleanup on all errors foreach (var consumer in m_Consumers) { try { // Remove Hardware.SetConsumerState(consumer, null); } catch { // Ignore any error } } // Forward throw; } // Remember path if (filePath != null) { m_AllFiles.Add(new FileStreamInformation { FilePath = filePath, VideoType = m_OriginalSettings.VideoType }); } // Remember the time LastActivationTime = DateTime.UtcNow; } catch { // Simply forget m_TransportStream.Dispose(); m_TransportStream = null; // Forward throw; } // Get the next free PID NextStreamIdentifier = m_TransportStream.NextPID; // Remember the streams we use ActiveSelection = result; // Attach to clients var createNotify = OnCreatedStream; // Report if (createNotify != null) { createNotify(this); } }