コード例 #1
0
        public static async Task ExtractSystemTemplates(ILogger logger, IDeviceProfileManager profileManager, IXmlSerializer xmlSerializer)
        {
            if (profileManager.Profiles.Count(p => p.ProfileType == DeviceProfileType.SystemTemplate) > 1)
            {
                // Don't load more than once.
                return;
            }

            // Load Resources into memory.
            const string NamespaceName = "Jellyfin.Plugin.Dlna.Profiles.Xml.";

            foreach (var name in _assembly.GetManifestResourceNames())
            {
                if (!name.StartsWith(NamespaceName, StringComparison.Ordinal))
                {
                    continue;
                }

                await using var stream = _assembly.GetManifestResourceStream(name);
                if (stream == null)
                {
                    logger.LogError("Unable to extract manifest resource for {Name}", name);
                    break;
                }

                var systemProfile = (DeviceProfile)xmlSerializer.DeserializeFromStream(typeof(DeviceProfile), stream);
                if (systemProfile != null)
                {
                    systemProfile.ProfileType = DeviceProfileType.SystemTemplate;
                    profileManager.AddProfile(systemProfile);
                }
            }
        }
コード例 #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContentDirectoryService"/> class.
 /// </summary>
 /// <param name="profileManager">The <see cref="IProfileManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="userDataManager">The <see cref="IUserDataManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="imageProcessor">The <see cref="IImageProcessor"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="libraryManager">The <see cref="ILibraryManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="userManager">The <see cref="IUserManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="logger">The <see cref="ILogger"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="localization">The <see cref="ILocalizationManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="mediaSourceManager">The <see cref="IMediaSourceManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="userViewManager">The <see cref="IUserViewManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="mediaEncoder">The <see cref="IMediaEncoder"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 /// <param name="tvSeriesManager">The <see cref="ITVSeriesManager"/> to use in the <see cref="ContentDirectoryService"/> instance.</param>
 public ContentDirectoryService(
     IDeviceProfileManager profileManager,
     IUserDataManager userDataManager,
     IImageProcessor imageProcessor,
     ILibraryManager libraryManager,
     IUserManager userManager,
     ILogger logger,
     ILocalizationManager localization,
     IMediaSourceManager mediaSourceManager,
     IUserViewManager userViewManager,
     IMediaEncoder mediaEncoder,
     ITVSeriesManager tvSeriesManager)
 {
     _profileManager     = profileManager;
     _logger             = logger;
     _userDataManager    = userDataManager;
     _imageProcessor     = imageProcessor;
     _libraryManager     = libraryManager;
     _userManager        = userManager;
     _localization       = localization;
     _mediaSourceManager = mediaSourceManager;
     _userViewManager    = userViewManager;
     _mediaEncoder       = mediaEncoder;
     _tvSeriesManager    = tvSeriesManager;
 }
コード例 #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ConnectionManagerService"/> class.
 /// </summary>
 /// <param name="profileManager">The <see cref="IProfileManager"/> for use with the <see cref="ConnectionManagerService"/> instance.</param>
 /// <param name="logger">The <see cref="ILogger"/> for use with the <see cref="ConnectionManagerService"/> instance.</param>
 public ConnectionManagerService(IDeviceProfileManager profileManager, ILogger logger)
 {
     _logger         = logger;
     _profileManager = profileManager;
 }
コード例 #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DlnaServerManager"/> class.
        /// </summary>
        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> instance.</param>
        /// <param name="appHost">The <see cref="IServerApplicationHost"/> instance.</param>
        /// <param name="libraryManager">The <see cref="ILibraryManager"/> instance.</param>
        /// <param name="userManager">The <see cref="IUserManager"/> instance.</param>
        /// <param name="profileManager">The <see cref="IProfileManager"/> instance.</param>
        /// <param name="imageProcessor">The <see cref="IImageProcessor"/> instance.</param>
        /// <param name="userDataManager">The <see cref="IUserDataManager"/> instance.</param>
        /// <param name="localizationManager">The <see cref="ILocalizationManager"/> instance.</param>
        /// <param name="mediaSourceManager">The <see cref="IMediaSourceManager"/> instance.</param>
        /// <param name="mediaEncoder">The <see cref="IMediaEncoder"/> instance.</param>
        /// <param name="networkManager">The <see cref="INetworkManager"/> instance.</param>
        /// <param name="userViewManager">The <see cref="IUserViewManager"/> instance.</param>
        /// <param name="tvSeriesManager">The <see cref="ITVSeriesManager"/> instance.</param>
        /// <param name="configurationManager">The <see cref="IConfigurationManager"/> instance.</param>
        /// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> instance.</param>
        /// <param name="xmlSerializer">The <see cref="IXmlSerializer"/> instance.</param>
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. :-> ServerString
#pragma warning disable CA1062 // Validate arguments of public methods. -> Created by DI.

        public DlnaServerManager(
            ILoggerFactory loggerFactory,
            IServerApplicationHost appHost,
            ILibraryManager libraryManager,
            IUserManager userManager,
            IDeviceProfileManager profileManager,
            IImageProcessor imageProcessor,
            IUserDataManager userDataManager,
            ILocalizationManager localizationManager,
            IMediaSourceManager mediaSourceManager,
            IMediaEncoder mediaEncoder,
            INetworkManager networkManager,
            IUserViewManager userViewManager,
            ITVSeriesManager tvSeriesManager,
            IConfigurationManager configurationManager,
            IHttpClientFactory httpClientFactory,
            IXmlSerializer xmlSerializer)
        {
            SsdpConfiguration.JellyfinVersion = appHost.ApplicationVersionString;

            // Changing serverId will cause dlna url links to become invalid between restarts.
            ServerId              = DlnaServerPlugin.Instance !.Configuration.ChangeIdOnStartup ? Guid.NewGuid() : Guid.Parse(appHost.SystemId);
            _networkManager       = networkManager;
            _appHost              = appHost;
            _logger               = loggerFactory.CreateLogger <DlnaServerManager>();
            _configurationManager = configurationManager;
            _profileManager       = profileManager;

            EventManager = new DlnaEventManager(_logger, httpClientFactory);

            // Link into the streaming API, so that headers etc can be performed.
            StreamingHelpers.StreamEvent ??= DlnaStreamHelper.StreamEventProcessor;

            _logger.LogDebug("DLNA Server : Starting Content Directory service.");
            ContentDirectory = new ContentDirectoryService(
                profileManager,
                userDataManager,
                imageProcessor,
                libraryManager,
                userManager,
                _logger,
                localizationManager,
                mediaSourceManager,
                userViewManager,
                mediaEncoder,
                tvSeriesManager);

            _logger.LogDebug("DLNA Server : Starting Connection Manager service.");
            ConnectionManager = new ConnectionManagerService(profileManager, _logger);

            var config = DlnaServerPlugin.Instance !.Configuration;
            // Get bind addresses or interfaces if not specified.
            var interfaces = config.BindAddresses;

            var bindInterfaces = _networkManager.GetInternalBindAddresses();

            if (interfaces.Length > 0)
            {
                // Select only the internal interfaces that are LAN and bound.
                var addresses = _networkManager.CreateIPCollection(interfaces, false, false);
                _bindAddresses = bindInterfaces.Where(i => addresses.Contains(i) &&
                                                      (i.AddressFamily == AddressFamily.InterNetwork || (i.AddressFamily == AddressFamily.InterNetworkV6 && i.Address.ScopeId != 0)))
                                 .ToArray();
            }
            else
            {
                _bindAddresses = bindInterfaces.Where(i => !i.IsLoopback() &&
                                                      (i.AddressFamily == AddressFamily.InterNetwork || (i.AddressFamily == AddressFamily.InterNetworkV6 && i.Address.ScopeId != 0)))
                                 .ToArray();
            }

            if (_bindAddresses.Length == 0)
            {
                // only use loop-backs if no other address available.
                _bindAddresses = bindInterfaces;
            }

            _publisher = new SsdpServerPublisher(
                configurationManager,
                _logger,
                loggerFactory,
                _networkManager,
                _bindAddresses,
                config.AliveMessageIntervalSeconds,
                config.EnableWindowsExplorerSupport);

            // Load system profiles into memory.
            ProfileHelper.ExtractSystemTemplates(_logger, _profileManager, xmlSerializer).GetAwaiter().GetResult();

            // Solves a race condition can occur when API receives input before DI initialization is complete.
            Instance = this;
        }
コード例 #5
0
        /// <summary>
        /// Adds the dlna headers.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="profileManager">The <see cref="IDeviceProfileManager"/> instance.</param>
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
        /// <param name="startTimeTicks">The start time in ticks.</param>
        /// <param name="request">The <see cref="HttpRequest"/>.</param>
        private static void AddDlnaHeaders(
            StreamState state,
            IHeaderDictionary responseHeaders,
            IDeviceProfileManager profileManager,
            bool isStaticallyStreamed,
            long?startTimeTicks,
            HttpRequest request)
        {
            if (state == null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (responseHeaders == null)
            {
                throw new ArgumentNullException(nameof(responseHeaders));
            }

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var enableDlnaHeaders = request.Query.TryGetValue("dlna", out _) ||
                                    !string.Equals(request.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.Ordinal);

            if (!enableDlnaHeaders)
            {
                return;
            }

            var profile = state.DeviceProfile;

            StringValues transferMode = request.Headers["transferMode.dlna.org"];

            responseHeaders.Add("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
            responseHeaders.Add("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");

            if (state.RunTimeTicks.HasValue)
            {
                if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
                {
                    var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
                    responseHeaders.Add("MediaInfo.sec", string.Format(
                                            CultureInfo.InvariantCulture,
                                            "SEC_Duration={0};",
                                            Convert.ToInt32(ms)));
                }

                if (!isStaticallyStreamed && profile != null)
                {
                    AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks);
                }
            }

            // if the profile hasn't been assigned see if there is one that matches.
            profile ??= profileManager.GetProfile(
                request.Headers,
                request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback,
                null);

            var audioCodec = state.ActualOutputAudioCodec;

            if (!state.IsVideoRequest)
            {
                responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
                                        profile,
                                        state.OutputContainer,
                                        audioCodec,
                                        state.OutputAudioBitrate,
                                        state.OutputAudioSampleRate,
                                        state.OutputAudioChannels,
                                        state.OutputAudioBitDepth,
                                        isStaticallyStreamed,
                                        state.RunTimeTicks,
                                        state.TranscodeSeekInfo));
            }
            else
            {
                var videoCodec = state.ActualOutputVideoCodec;

                responseHeaders.Add(
                    "contentFeatures.dlna.org",
                    ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
            }
        }
コード例 #6
0
        /// <summary>
        /// Applies the device profile to the streamstate.
        /// </summary>
        /// <param name="state">A <see cref="StreamState"/> instance.</param>
        /// <param name="deviceManager">The <see cref="IDeviceManager"/> instance.</param>
        /// <param name="profileManager">The <see cref="IDeviceProfileManager"/> instance.</param>
        /// <param name="request">A <see cref="HttpRequest"/> instance.</param>
        /// <param name="deviceProfileId">Optional. Device profile id. </param>
        /// <param name="static">True if static.</param>
        private static void ApplyDeviceProfileSettings(
            StreamState state,
            IDeviceManager deviceManager,
            IDeviceProfileManager profileManager,
            HttpRequest request,
            string?deviceProfileId,
            bool? @static)
        {
            if (state == null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (deviceManager == null)
            {
                throw new ArgumentNullException(nameof(deviceManager));
            }

            if (!string.IsNullOrWhiteSpace(deviceProfileId))
            {
                state.DeviceProfile = profileManager.GetProfile(Guid.Parse(deviceProfileId));

                if (state.DeviceProfile == null)
                {
                    var caps = deviceManager.GetCapabilities(deviceProfileId);
                    state.DeviceProfile = profileManager.GetProfile(
                        request.Headers,
                        request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback,
                        caps?.DeviceProfile);
                }
            }

            var profile = state.DeviceProfile;

            if (profile == null)
            {
                // Don't use settings from the default profile.
                // Only use a specific profile if it was requested.
                return;
            }

            var audioCodec = state.ActualOutputAudioCodec;
            var videoCodec = state.ActualOutputVideoCodec;

            var mediaProfile = !state.IsVideoRequest
                ? profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth)
                : profile.GetVideoMediaProfile(
                state.OutputContainer,
                audioCodec,
                videoCodec,
                state.OutputWidth,
                state.OutputHeight,
                state.TargetVideoBitDepth,
                state.OutputVideoBitrate,
                state.TargetVideoProfile,
                state.TargetVideoLevel,
                state.TargetFramerate,
                state.TargetPacketLength,
                state.TargetTimestamp,
                state.IsTargetAnamorphic,
                state.IsTargetInterlaced,
                state.TargetRefFrames,
                state.TargetVideoStreamCount,
                state.TargetAudioStreamCount,
                state.TargetVideoCodecTag,
                state.IsTargetAVC);

            if (mediaProfile != null)
            {
                state.MimeType = mediaProfile.MimeType;
            }

            if (@static.HasValue && @static.Value)
            {
                return;
            }

            var transcodingProfile = !state.IsVideoRequest ? profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec);

            if (transcodingProfile == null)
            {
                return;
            }

            state.EstimateContentLength = transcodingProfile.EstimateContentLength;
            // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
            state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;

            if (state.VideoRequest == null)
            {
                return;
            }

            state.VideoRequest.CopyTimestamps            = transcodingProfile.CopyTimestamps;
            state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
        }