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)
{
var mediaSource = await MediaSourceManager.OpenLiveStream(state.MediaSource.OpenToken, false, cancellationTokenSource.Token)
.ConfigureAwait(false);
var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
{
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)
{

View File

@ -698,7 +698,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
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,
GetInputArgument(state),
threads,
@ -712,7 +712,7 @@ namespace MediaBrowser.Api.Playback.Hls
).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,
GetInputArgument(state),
threads,

View File

@ -61,14 +61,12 @@ namespace MediaBrowser.Api.Playback
public string MediaSourceId { get; set; }
}
[Route("/MediaSources/Open", "POST", Summary = "Opens a media source")]
public class OpenMediaSource : IReturn<MediaSourceInfo>
[Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
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
{
[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)
{
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);
}
@ -177,11 +200,11 @@ namespace MediaBrowser.Api.Playback
return result;
}
private void SetDeviceSpecificData(string itemId,
PlaybackInfoResponse result,
DeviceProfile profile,
AuthorizationInfo auth,
int? maxBitrate,
private void SetDeviceSpecificData(string itemId,
PlaybackInfoResponse result,
DeviceProfile profile,
AuthorizationInfo auth,
int? maxBitrate,
long startTimeTicks,
string mediaSourceId,
int? audioStreamIndex,

View File

@ -2,6 +2,7 @@
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Threading;
@ -84,11 +85,11 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Opens the media source.
/// </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="cancellationToken">The cancellation token.</param>
/// <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>
/// Gets the live stream.

View File

@ -803,6 +803,12 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link>
</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">
<Link>MediaInfo\MediaProtocol.cs</Link>
</Compile>

View File

@ -759,6 +759,12 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link>
</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">
<Link>MediaInfo\MediaProtocol.cs</Link>
</Compile>

View File

@ -172,5 +172,11 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="rememberCredentials">if set to <c>true</c> [remember credentials].</param>
/// <returns>Task.</returns>
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\NameIdPair.cs" />
<Compile Include="Dto\NameValuePair.cs" />
<Compile Include="MediaInfo\LiveStreamRequest.cs" />
<Compile Include="MediaInfo\LiveStreamResponse.cs" />
<Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
<Compile Include="MediaInfo\PlaybackInfoResponse.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.Library;
using MediaBrowser.Controller.MediaEncoding;
@ -8,13 +7,14 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Server.Implementations.LiveTv;
namespace MediaBrowser.Server.Implementations.Library
{
@ -23,16 +23,18 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IItemRepository _itemRepo;
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
private readonly IJsonSerializer _jsonSerializer;
private IMediaSourceProvider[] _providers;
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;
_userManager = userManager;
_libraryManager = libraryManager;
_logger = logger;
_jsonSerializer = jsonSerializer;
}
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 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);
try
{
var tuple = GetProvider(openToken);
var tuple = GetProvider(request.OpenToken);
var provider = tuple.Item1;
var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
@ -344,12 +346,19 @@ namespace MediaBrowser.Server.Implementations.Library
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
{

View File

@ -14,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Devices;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
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>
/// Updates the now playing item id.
/// </summary>
/// <param name="session">The session.</param>
/// <param name="info">The information.</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))
{
@ -319,29 +328,27 @@ namespace MediaBrowser.Server.Implementations.Session
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;
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
{
info.Item = current;
}
info.Item.RunTimeTicks = runtimeTicks;
}
session.NowPlayingItem = info.Item;
@ -432,6 +439,12 @@ namespace MediaBrowser.Server.Implementations.Session
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 (!string.IsNullOrEmpty(device.CustomName))
@ -570,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Session
? null
: _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)
{
@ -652,7 +665,7 @@ namespace MediaBrowser.Server.Implementations.Session
? null
: _libraryManager.GetItemById(new Guid(info.ItemId));
UpdateNowPlayingItem(session, info, libraryItem);
await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
var users = GetUsers(session);
@ -731,7 +744,9 @@ namespace MediaBrowser.Server.Implementations.Session
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
{
@ -1439,10 +1454,10 @@ namespace MediaBrowser.Server.Implementations.Session
/// </summary>
/// <param name="item">The item.</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>
/// <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)
{
@ -1593,9 +1608,9 @@ namespace MediaBrowser.Server.Implementations.Session
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;

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);
RegisterSingleInstance(ChannelManager);
MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"));
MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer);
RegisterSingleInstance(MediaSourceManager);
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);