update live stream generation

This commit is contained in:
Luke Pulverenti 2015-03-29 12:45:16 -04:00
parent 87bf3bbb8f
commit a79962b7eb
13 changed files with 146 additions and 50 deletions

View File

@ -936,10 +936,13 @@ namespace MediaBrowser.Api.Playback
if (state.MediaSource.RequiresOpening) if (state.MediaSource.RequiresOpening)
{ {
var mediaSource = await MediaSourceManager.OpenLiveStream(state.MediaSource.OpenToken, false, cancellationTokenSource.Token) var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
.ConfigureAwait(false); {
OpenToken = state.MediaSource.OpenToken
AttachMediaSourceInfo(state, mediaSource, state.VideoRequest, state.RequestedUrl); }, false, cancellationTokenSource.Token).ConfigureAwait(false);
AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.VideoRequest, state.RequestedUrl);
if (state.VideoRequest != null) if (state.VideoRequest != null)
{ {

View File

@ -698,7 +698,7 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d.ts"; var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d.ts";
return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header -sc_threshold 0 {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
inputModifier, inputModifier,
GetInputArgument(state), GetInputArgument(state),
threads, threads,
@ -712,7 +712,7 @@ namespace MediaBrowser.Api.Playback.Hls
).Trim(); ).Trim();
} }
return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"", return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier, inputModifier,
GetInputArgument(state), GetInputArgument(state),
threads, threads,

View File

@ -61,14 +61,12 @@ namespace MediaBrowser.Api.Playback
public string MediaSourceId { get; set; } public string MediaSourceId { get; set; }
} }
[Route("/MediaSources/Open", "POST", Summary = "Opens a media source")] [Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
public class OpenMediaSource : IReturn<MediaSourceInfo> public class OpenMediaSource : LiveStreamRequest, IReturn<LiveStreamResponse>
{ {
[ApiMember(Name = "OpenToken", Description = "OpenToken", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string OpenToken { get; set; }
} }
[Route("/MediaSources/Close", "POST", Summary = "Closes a media source")] [Route("/LiveStreams/Close", "POST", Summary = "Closes a media source")]
public class CloseMediaSource : IReturnVoid public class CloseMediaSource : IReturnVoid
{ {
[ApiMember(Name = "LiveStreamId", Description = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] [ApiMember(Name = "LiveStreamId", Description = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -103,7 +101,32 @@ namespace MediaBrowser.Api.Playback
public async Task<object> Post(OpenMediaSource request) public async Task<object> Post(OpenMediaSource request)
{ {
var result = await _mediaSourceManager.OpenLiveStream(request.OpenToken, false, CancellationToken.None).ConfigureAwait(false); var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
var result = await _mediaSourceManager.OpenLiveStream(request, false, CancellationToken.None).ConfigureAwait(false);
var profile = request.DeviceProfile;
if (profile == null)
{
var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
if (caps != null)
{
profile = caps.DeviceProfile;
}
}
if (profile != null)
{
var item = _libraryManager.GetItemById(request.ItemId);
SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex, request.SubtitleStreamIndex);
}
if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl))
{
result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId;
}
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
@ -177,11 +200,11 @@ namespace MediaBrowser.Api.Playback
return result; return result;
} }
private void SetDeviceSpecificData(string itemId, private void SetDeviceSpecificData(string itemId,
PlaybackInfoResponse result, PlaybackInfoResponse result,
DeviceProfile profile, DeviceProfile profile,
AuthorizationInfo auth, AuthorizationInfo auth,
int? maxBitrate, int? maxBitrate,
long startTimeTicks, long startTimeTicks,
string mediaSourceId, string mediaSourceId,
int? audioStreamIndex, int? audioStreamIndex,

View File

@ -2,6 +2,7 @@
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
@ -84,11 +85,11 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Opens the media source. /// Opens the media source.
/// </summary> /// </summary>
/// <param name="openToken">The open token.</param> /// <param name="request">The request.</param>
/// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</param> /// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns> /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> OpenLiveStream(string openToken, bool enableAutoClose, CancellationToken cancellationToken); Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the live stream. /// Gets the live stream.

View File

@ -803,6 +803,12 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link> <Link>MediaInfo\IBlurayExaminer.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamRequest.cs">
<Link>MediaInfo\LiveStreamRequest.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
<Link>MediaInfo\LiveStreamResponse.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link> <Link>MediaInfo\MediaProtocol.cs</Link>
</Compile> </Compile>

View File

@ -759,6 +759,12 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link> <Link>MediaInfo\IBlurayExaminer.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamRequest.cs">
<Link>MediaInfo\LiveStreamRequest.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
<Link>MediaInfo\LiveStreamResponse.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link> <Link>MediaInfo\MediaProtocol.cs</Link>
</Compile> </Compile>

View File

@ -172,5 +172,11 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="rememberCredentials">if set to <c>true</c> [remember credentials].</param> /// <param name="rememberCredentials">if set to <c>true</c> [remember credentials].</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task AuthenticateOffline(UserDto user, string password, bool rememberCredentials); Task AuthenticateOffline(UserDto user, string password, bool rememberCredentials);
/// <summary>
/// Gets the offline users.
/// </summary>
/// <returns>Task&lt;List&lt;UserDto&gt;&gt;.</returns>
Task<List<UserDto>> GetOfflineUsers();
} }
} }

View File

@ -141,6 +141,8 @@
<Compile Include="Dto\MetadataEditorInfo.cs" /> <Compile Include="Dto\MetadataEditorInfo.cs" />
<Compile Include="Dto\NameIdPair.cs" /> <Compile Include="Dto\NameIdPair.cs" />
<Compile Include="Dto\NameValuePair.cs" /> <Compile Include="Dto\NameValuePair.cs" />
<Compile Include="MediaInfo\LiveStreamRequest.cs" />
<Compile Include="MediaInfo\LiveStreamResponse.cs" />
<Compile Include="MediaInfo\PlaybackInfoRequest.cs" /> <Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
<Compile Include="MediaInfo\PlaybackInfoResponse.cs" /> <Compile Include="MediaInfo\PlaybackInfoResponse.cs" />
<Compile Include="Dto\MediaSourceType.cs" /> <Compile Include="Dto\MediaSourceType.cs" />

View File

@ -0,0 +1,16 @@
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.MediaInfo
{
public class LiveStreamRequest
{
public string OpenToken { get; set; }
public string UserId { get; set; }
public int? MaxStreamingBitrate { get; set; }
public long? StartTimeTicks { get; set; }
public int? AudioStreamIndex { get; set; }
public int? SubtitleStreamIndex { get; set; }
public string ItemId { get; set; }
public DeviceProfile DeviceProfile { get; set; }
}
}

View File

@ -0,0 +1,9 @@
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.MediaInfo
{
public class LiveStreamResponse
{
public MediaSourceInfo MediaSource { get; set; }
}
}

View File

@ -1,5 +1,4 @@
using System.Collections.Concurrent; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
@ -8,13 +7,14 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Server.Implementations.LiveTv;
namespace MediaBrowser.Server.Implementations.Library namespace MediaBrowser.Server.Implementations.Library
{ {
@ -23,16 +23,18 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IItemRepository _itemRepo; private readonly IItemRepository _itemRepo;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IJsonSerializer _jsonSerializer;
private IMediaSourceProvider[] _providers; private IMediaSourceProvider[] _providers;
private readonly ILogger _logger; private readonly ILogger _logger;
public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger) public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer)
{ {
_itemRepo = itemRepo; _itemRepo = itemRepo;
_userManager = userManager; _userManager = userManager;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_logger = logger; _logger = logger;
_jsonSerializer = jsonSerializer;
} }
public void AddParts(IEnumerable<IMediaSourceProvider> providers) public void AddParts(IEnumerable<IMediaSourceProvider> providers)
@ -317,13 +319,13 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>(); private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>();
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
public async Task<MediaSourceInfo> OpenLiveStream(string openToken, bool enableAutoClose, CancellationToken cancellationToken) public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
{ {
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try try
{ {
var tuple = GetProvider(openToken); var tuple = GetProvider(request.OpenToken);
var provider = tuple.Item1; var provider = tuple.Item1;
var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false); var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
@ -344,12 +346,19 @@ namespace MediaBrowser.Server.Implementations.Library
StartCloseTimer(); StartCloseTimer();
} }
if (!string.IsNullOrWhiteSpace(mediaSource.TranscodingUrl)) var json = _jsonSerializer.SerializeToString(mediaSource);
var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
mediaSource.TranscodingUrl += "&LiveStreamId=" + mediaSource.LiveStreamId; var user = _userManager.GetUserById(request.UserId);
SetUserProperties(clone, user);
} }
return mediaSource; return new LiveStreamResponse
{
MediaSource = clone
};
} }
finally finally
{ {

View File

@ -14,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Devices; using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.Library; using MediaBrowser.Model.Library;
@ -304,13 +305,21 @@ namespace MediaBrowser.Server.Implementations.Session
} }
} }
private async Task<MediaSourceInfo> GetMediaSource(BaseItem item, string mediaSourceId)
{
var sources = await _mediaSourceManager.GetPlayackMediaSources(item.Id.ToString("N"), false, CancellationToken.None)
.ConfigureAwait(false);
return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
}
/// <summary> /// <summary>
/// Updates the now playing item id. /// Updates the now playing item id.
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="info">The information.</param> /// <param name="info">The information.</param>
/// <param name="libraryItem">The library item.</param> /// <param name="libraryItem">The library item.</param>
private void UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem) private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem)
{ {
if (string.IsNullOrWhiteSpace(info.MediaSourceId)) if (string.IsNullOrWhiteSpace(info.MediaSourceId))
{ {
@ -319,29 +328,27 @@ namespace MediaBrowser.Server.Implementations.Session
if (!string.IsNullOrWhiteSpace(info.ItemId) && info.Item == null && libraryItem != null) if (!string.IsNullOrWhiteSpace(info.ItemId) && info.Item == null && libraryItem != null)
{ {
var runtimeTicks = libraryItem.RunTimeTicks;
if (!string.Equals(info.ItemId, info.MediaSourceId) &&
!string.IsNullOrWhiteSpace(info.MediaSourceId))
{
var runtimeItem = _libraryManager.GetItemById(new Guid(info.MediaSourceId)) ??
_libraryManager.GetItemById(info.ItemId);
runtimeTicks = runtimeItem.RunTimeTicks;
}
var current = session.NowPlayingItem; var current = session.NowPlayingItem;
if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase)) if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase))
{ {
info.Item = GetItemInfo(libraryItem, libraryItem, info.MediaSourceId); var runtimeTicks = libraryItem.RunTimeTicks;
var mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId).ConfigureAwait(false);
if (mediaSource != null)
{
runtimeTicks = mediaSource.RunTimeTicks;
}
info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource);
info.Item.RunTimeTicks = runtimeTicks;
} }
else else
{ {
info.Item = current; info.Item = current;
} }
info.Item.RunTimeTicks = runtimeTicks;
} }
session.NowPlayingItem = info.Item; session.NowPlayingItem = info.Item;
@ -432,6 +439,12 @@ namespace MediaBrowser.Server.Implementations.Session
device = device ?? _deviceManager.GetDevice(deviceId); device = device ?? _deviceManager.GetDevice(deviceId);
if (device == null)
{
var userIdString = userId.HasValue ? userId.Value.ToString("N") : null;
device = await _deviceManager.RegisterDevice(deviceId, deviceName, appName, appVersion, userIdString).ConfigureAwait(false);
}
if (device != null) if (device != null)
{ {
if (!string.IsNullOrEmpty(device.CustomName)) if (!string.IsNullOrEmpty(device.CustomName))
@ -570,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Session
? null ? null
: _libraryManager.GetItemById(new Guid(info.ItemId)); : _libraryManager.GetItemById(new Guid(info.ItemId));
UpdateNowPlayingItem(session, info, libraryItem); await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode) if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)
{ {
@ -652,7 +665,7 @@ namespace MediaBrowser.Server.Implementations.Session
? null ? null
: _libraryManager.GetItemById(new Guid(info.ItemId)); : _libraryManager.GetItemById(new Guid(info.ItemId));
UpdateNowPlayingItem(session, info, libraryItem); await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
var users = GetUsers(session); var users = GetUsers(session);
@ -731,7 +744,9 @@ namespace MediaBrowser.Server.Implementations.Session
if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase)) if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase))
{ {
info.Item = GetItemInfo(libraryItem, libraryItem, info.MediaSourceId); var mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId).ConfigureAwait(false);
info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource);
} }
else else
{ {
@ -1439,10 +1454,10 @@ namespace MediaBrowser.Server.Implementations.Session
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="chapterOwner">The chapter owner.</param> /// <param name="chapterOwner">The chapter owner.</param>
/// <param name="mediaSourceId">The media source identifier.</param> /// <param name="mediaSource">The media source.</param>
/// <returns>BaseItemInfo.</returns> /// <returns>BaseItemInfo.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
private BaseItemInfo GetItemInfo(BaseItem item, BaseItem chapterOwner, string mediaSourceId) private BaseItemInfo GetItemInfo(BaseItem item, BaseItem chapterOwner, MediaSourceInfo mediaSource)
{ {
if (item == null) if (item == null)
{ {
@ -1593,9 +1608,9 @@ namespace MediaBrowser.Server.Implementations.Session
info.Chapters = _dtoService.GetChapterInfoDtos(chapterOwner).ToList(); info.Chapters = _dtoService.GetChapterInfoDtos(chapterOwner).ToList();
} }
if (!string.IsNullOrWhiteSpace(mediaSourceId)) if (mediaSource != null)
{ {
info.MediaStreams = _mediaSourceManager.GetMediaStreams(mediaSourceId).ToList(); info.MediaStreams = mediaSource.MediaStreams;
} }
return info; return info;

View File

@ -472,7 +472,7 @@ namespace MediaBrowser.Server.Startup.Common
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient); ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
RegisterSingleInstance(ChannelManager); RegisterSingleInstance(ChannelManager);
MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager")); MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer);
RegisterSingleInstance(MediaSourceManager); RegisterSingleInstance(MediaSourceManager);
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager); SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);