diff options
| -rw-r--r-- | MediaBrowser.Dlna/PlayTo/Device.cs | 1541 | ||||
| -rw-r--r-- | MediaBrowser.Dlna/PlayTo/DlnaController.cs | 970 | ||||
| -rw-r--r-- | MediaBrowser.sln | 513 |
3 files changed, 1535 insertions, 1489 deletions
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index dd416b5a4..6b5e8de9f 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -1,751 +1,790 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace MediaBrowser.Dlna.PlayTo -{ - public sealed class Device : IDisposable - { - const string ServiceAvtransportId = "urn:upnp-org:serviceId:AVTransport"; - const string ServiceRenderingId = "urn:upnp-org:serviceId:RenderingControl"; - - #region Fields & Properties - - private Timer _timer; - - public DeviceProperties Properties { get; set; } - - private int _muteVol; - public bool IsMuted - { - get - { - return _muteVol > 0; - } - } - - private string _currentId = String.Empty; - public string CurrentId - { - get - { - return _currentId; - } - set - { - if (_currentId == value) - return; - _currentId = value; - NotifyCurrentIdChanged(value); - } - } - - public int Volume { get; set; } - - public TimeSpan Duration { get; set; } - - private TimeSpan _position = TimeSpan.FromSeconds(0); - public TimeSpan Position - { - get - { - return _position; - } - set - { - _position = value; - } - } - - private string _transportState = String.Empty; - public string TransportState - { - get - { - return _transportState; - } - set - { - if (_transportState == value) - return; - - _transportState = value; - - if (value == "PLAYING" || value == "STOPPED") - NotifyPlaybackChanged(value == "STOPPED"); - } - } - - public bool IsPlaying - { - get - { - return TransportState == "PLAYING"; - } - } - - public bool IsTransitioning - { - get - { - return (TransportState == "TRANSITIONING"); - } - } - - public bool IsPaused - { - get - { - return TransportState == "PAUSED" || TransportState == "PAUSED_PLAYBACK"; - } - } - - public bool IsStopped - { - get - { - return (TransportState == "STOPPED"); - } - } - - public DateTime UpdateTime { get; private set; } - - #endregion - - private readonly IHttpClient _httpClient; - private readonly ILogger _logger; - - public Device(DeviceProperties deviceProperties, IHttpClient httpClient, ILogger logger) - { - Properties = deviceProperties; - _httpClient = httpClient; - _logger = logger; - } - - private int GetTimerIntervalMs() - { - return 10000; - } - - public void Start() - { - UpdateTime = DateTime.UtcNow; - - var interval = GetTimerIntervalMs(); - - _timer = new Timer(TimerCallback, null, interval, interval); - } - - private void RestartTimer() - { - var interval = GetTimerIntervalMs(); - - _timer.Change(interval, interval); - } - - private void StopTimer() - { - _timer.Change(Timeout.Infinite, Timeout.Infinite); - } - - #region Commanding - - public Task<bool> VolumeDown(bool mute = false) - { - var sendVolume = (Volume - 5) > 0 ? Volume - 5 : 0; - if (mute && _muteVol == 0) - { - sendVolume = 0; - _muteVol = Volume; - } - return SetVolume(sendVolume); - } - - public Task<bool> VolumeUp(bool unmute = false) - { - var sendVolume = (Volume + 5) < 100 ? Volume + 5 : 100; - if (unmute && _muteVol > 0) - sendVolume = _muteVol; - _muteVol = 0; - return SetVolume(sendVolume); - } - - public Task ToggleMute() - { - if (_muteVol == 0) - { - _muteVol = Volume; - return SetVolume(0); - } - - var tmp = _muteVol; - _muteVol = 0; - return SetVolume(tmp); - } - - public async Task<bool> SetVolume(int value) - { - var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume"); - if (command == null) - return true; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, value)) - .ConfigureAwait(false); - Volume = value; - return true; - } - - public async Task<TimeSpan> Seek(TimeSpan value) - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek"); - if (command == null) - return value; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, String.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME")) - .ConfigureAwait(false); - - return value; - } - - public async Task<bool> SetAvTransport(string url, string header, string metaData) - { - StopTimer(); - - TransportState = "STOPPED"; - CurrentId = "0"; - - await Task.Delay(50).ConfigureAwait(false); - - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI"); - if (command == null) - return false; - - var dictionary = new Dictionary<string, string> - { - {"CurrentURI", url}, - {"CurrentURIMetaData", CreateDidlMeta(metaData)} - }; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, url, dictionary), header) - .ConfigureAwait(false); - - if (!IsPlaying) - { - await Task.Delay(50).ConfigureAwait(false); - await SetPlay().ConfigureAwait(false); - } - - _count = 5; - RestartTimer(); - - return true; - } - - private string CreateDidlMeta(string value) - { - if (value == null) - return String.Empty; - - var escapedData = value.Replace("<", "<").Replace(">", ">"); - - return String.Format(BaseDidl, escapedData.Replace("\r\n", "")); - } - - private const string BaseDidl = "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">{0}</DIDL-Lite>"; - - public async Task<bool> SetNextAvTransport(string value, string header, string metaData) - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetNextAVTransportURI"); - if (command == null) - return false; - - var dictionary = new Dictionary<string, string> - { - {"NextURI", value}, - {"NextURIMetaData", CreateDidlMeta(metaData)} - }; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, value, dictionary), header) - .ConfigureAwait(false); - - await Task.Delay(100).ConfigureAwait(false); - - return true; - } - - public async Task<bool> SetPlay() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play"); - if (command == null) - return false; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) - .ConfigureAwait(false); - - _count = 5; - return true; - } - - public async Task<bool> SetStop() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop"); - if (command == null) - return false; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) - .ConfigureAwait(false); - - await Task.Delay(50).ConfigureAwait(false); - _count = 4; - return true; - } - - public async Task<bool> SetPause() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause"); - if (command == null) - return false; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 0)) - .ConfigureAwait(false); - - await Task.Delay(50).ConfigureAwait(false); - TransportState = "PAUSED_PLAYBACK"; - return true; - } - - #endregion - - #region Get data - - // TODO: What is going on here - int _count = 5; - - private async void TimerCallback(object sender) - { - if (_disposed) - return; - - StopTimer(); - - try - { - var hasTrack = await GetPositionInfo().ConfigureAwait(false); - - // TODO: Why make these requests if hasTrack==false? - if (_count > 5) - { - await GetTransportInfo().ConfigureAwait(false); - if (!hasTrack) - { - await GetMediaInfo().ConfigureAwait(false); - } - await GetVolume().ConfigureAwait(false); - _count = 0; - } - } - catch (Exception ex) - { - _logger.ErrorException("Error updating device info", ex); - } - - _count++; - if (_disposed) - return; - - RestartTimer(); - } - - private async Task GetVolume() - { - var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume"); - if (command == null) - return; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) - .ConfigureAwait(false); - - if (result == null || result.Document == null) - return; - - var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null); - var volumeValue = volume == null ? null : volume.Value; - - if (volumeValue == null) - return; - - Volume = Int32.Parse(volumeValue); - - //Reset the Mute value if Volume is bigger than zero - if (Volume > 0 && _muteVol > 0) - { - _muteVol = 0; - } - } - - private async Task GetTransportInfo() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo"); - if (command == null) - return; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - if (service == null) - return; - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) - .ConfigureAwait(false); - - if (result == null || result.Document == null) - return; - - var transportState = - result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null); - - var transportStateValue = transportState == null ? null : transportState.Value; - - if (transportStateValue != null) - TransportState = transportStateValue; - - UpdateTime = DateTime.UtcNow; - } - - private async Task GetMediaInfo() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo"); - if (command == null) - return; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) - .ConfigureAwait(false); - - if (result == null || result.Document == null) - return; - - var track = result.Document.Descendants("CurrentURIMetaData").Select(i => i.Value).FirstOrDefault(); - - if (String.IsNullOrEmpty(track)) - { - CurrentId = "0"; - return; - } - - var uPnpResponse = XElement.Parse(track); - - var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse; - - var uTrack = uParser.CreateObjectFromXML(new uParserObject - { - Type = e.GetValue(uPnpNamespaces.uClass), - Element = e - }); - - if (uTrack != null) - CurrentId = uTrack.Id; - } - - private async Task<bool> GetPositionInfo() - { - var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo"); - if (command == null) - return true; - - var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - - if (service == null) - { - throw new InvalidOperationException("Unable to find service"); - } - - var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) - .ConfigureAwait(false); - - if (result == null || result.Document == null) - return true; - - var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null); - var duration = durationElem == null ? null : durationElem.Value; - - if (duration != null) - { - Duration = TimeSpan.Parse(duration); - } - - var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null); - var position = positionElem == null ? null : positionElem.Value; - - if (position != null) - { - Position = TimeSpan.Parse(position); - } - - var track = result.Document.Descendants("TrackMetaData").Select(i => i.Value) - .FirstOrDefault(); - - if (String.IsNullOrEmpty(track)) - { - //If track is null, some vendors do this, use GetMediaInfo instead - return false; - } - - var uPnpResponse = XElement.Parse(track); - - var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse; - - var uTrack = uBaseObject.Create(e); - - if (uTrack == null) - return true; - - CurrentId = uTrack.Id; - - return true; - } - - #endregion - - #region From XML - - private async Task GetAVProtocolAsync() - { - var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); - if (avService == null) - return; - - var url = avService.SCPDURL; - if (!url.Contains("/")) - url = "/dmr/" + url; - if (!url.StartsWith("/")) - url = "/" + url; - - var httpClient = new SsdpHttpClient(_httpClient); - var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); - - AvCommands = TransportCommands.Create(document); - } - - private async Task GetRenderingProtocolAsync() - { - var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); - - if (avService == null) - return; - string url = avService.SCPDURL; - if (!url.Contains("/")) - url = "/dmr/" + url; - if (!url.StartsWith("/")) - url = "/" + url; - - var httpClient = new SsdpHttpClient(_httpClient); - var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); - - RendererCommands = TransportCommands.Create(document); - } - - internal TransportCommands AvCommands - { - get; - set; - } - - internal TransportCommands RendererCommands - { - get; - set; - } - - public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, ILogger logger) - { - var ssdpHttpClient = new SsdpHttpClient(httpClient); - - var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false); - - var deviceProperties = new DeviceProperties(); - - var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault(); - if (name != null) - deviceProperties.Name = name.Value; - - var name2 = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault(); - if (name2 != null) - deviceProperties.Name = name2.Value; - - var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault(); - if (model != null) - deviceProperties.ModelName = model.Value; - - var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault(); - if (modelNumber != null) - deviceProperties.ModelNumber = modelNumber.Value; - - var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault(); - if (uuid != null) - deviceProperties.UUID = uuid.Value; - - var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault(); - if (manufacturer != null) - deviceProperties.Manufacturer = manufacturer.Value; - - var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault(); - if (manufacturerUrl != null) - deviceProperties.ManufacturerUrl = manufacturerUrl.Value; - - var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault(); - if (presentationUrl != null) - deviceProperties.PresentationUrl = presentationUrl.Value; - - - deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port); - - var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault(); - - if (icon != null) - { - deviceProperties.Icon = uIcon.Create(icon); - } - - var isRenderer = false; - - foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList"))) - { - if (services == null) - return null; - - var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service")); - - if (servicesList == null) - return null; - - foreach (var element in servicesList) - { - var service = uService.Create(element); - - if (service != null) - { - deviceProperties.Services.Add(service); - if (service.ServiceId == ServiceAvtransportId) - { - isRenderer = true; - } - } - } - } - - if (isRenderer) - { - - var device = new Device(deviceProperties, httpClient, logger); - - await device.GetRenderingProtocolAsync().ConfigureAwait(false); - await device.GetAVProtocolAsync().ConfigureAwait(false); - - return device; - } - - return null; - } - - #endregion - - #region Events - - public event EventHandler<TransportStateEventArgs> PlaybackChanged; - public event EventHandler<CurrentIdEventArgs> CurrentIdChanged; - - private void NotifyPlaybackChanged(bool value) - { - if (PlaybackChanged != null) - { - PlaybackChanged.Invoke(this, new TransportStateEventArgs - { - Stopped = IsStopped - }); - } - } - - private void NotifyCurrentIdChanged(string value) - { - if (CurrentIdChanged != null) - CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value)); - } - - #endregion - - #region IDisposable - - bool _disposed; - public void Dispose() - { - if (!_disposed) - { - _disposed = true; - _timer.Dispose(); - } - } - - #endregion - - public override string ToString() - { - return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl); - } - } -} +using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace MediaBrowser.Dlna.PlayTo
+{
+ public sealed class Device : IDisposable
+ {
+ const string ServiceAvtransportId = "urn:upnp-org:serviceId:AVTransport";
+ const string ServiceRenderingId = "urn:upnp-org:serviceId:RenderingControl";
+
+ #region Fields & Properties
+
+ private Timer _timer;
+
+ public DeviceProperties Properties { get; set; }
+
+ private int _muteVol;
+ public bool IsMuted
+ {
+ get
+ {
+ return _muteVol > 0;
+ }
+ }
+
+ private string _currentId = String.Empty;
+ public string CurrentId
+ {
+ get
+ {
+ return _currentId;
+ }
+ set
+ {
+ if (_currentId == value)
+ return;
+ _currentId = value;
+ NotifyCurrentIdChanged(value);
+ }
+ }
+
+ public int Volume { get; set; }
+
+ public TimeSpan Duration { get; set; }
+
+ private TimeSpan _position = TimeSpan.FromSeconds(0);
+ public TimeSpan Position
+ {
+ get
+ {
+ return _position;
+ }
+ set
+ {
+ _position = value;
+ }
+ }
+
+ private string _transportState = String.Empty;
+ public string TransportState
+ {
+ get
+ {
+ return _transportState;
+ }
+ set
+ {
+ if (_transportState == value)
+ return;
+
+ _transportState = value;
+
+ if (value == TRANSPORTSTATE.PLAYING || value == TRANSPORTSTATE.STOPPED)
+ NotifyPlaybackChanged(value == TRANSPORTSTATE.STOPPED);
+ }
+ }
+
+ public bool IsPlaying
+ {
+ get
+ {
+ return TransportState == TRANSPORTSTATE.PLAYING;
+ }
+ }
+
+ public bool IsTransitioning
+ {
+ get
+ {
+ return (TransportState == TRANSPORTSTATE.TRANSITIONING);
+ }
+ }
+
+ public bool IsPaused
+ {
+ get
+ {
+ return TransportState == TRANSPORTSTATE.PAUSED || TransportState == TRANSPORTSTATE.PAUSED_PLAYBACK;
+ }
+ }
+
+ public bool IsStopped
+ {
+ get
+ {
+ return TransportState == TRANSPORTSTATE.STOPPED;
+ }
+ }
+
+ public DateTime UpdateTime { get; private set; }
+
+ #endregion
+
+ private readonly IHttpClient _httpClient;
+ private readonly ILogger _logger;
+
+ public Device(DeviceProperties deviceProperties, IHttpClient httpClient, ILogger logger)
+ {
+ Properties = deviceProperties;
+ _httpClient = httpClient;
+ _logger = logger;
+ }
+
+ private int GetPlaybackTimerIntervalMs()
+ {
+ return 2000;
+ }
+
+ private int GetInactiveTimerIntervalMs()
+ {
+ return 20000;
+ }
+
+ public void Start()
+ {
+ UpdateTime = DateTime.UtcNow;
+
+ var interval = GetPlaybackTimerIntervalMs();
+
+ _timer = new Timer(TimerCallback, null, interval, interval);
+ }
+
+ private void RestartTimer()
+ {
+ var interval = GetPlaybackTimerIntervalMs();
+
+ _timer.Change(interval, interval);
+ }
+
+
+ /// <summary>
+ /// Restarts the timer in inactive mode.
+ /// </summary>
+ private void RestartTimerInactive()
+ {
+ var interval = GetInactiveTimerIntervalMs();
+
+ _timer.Change(interval, interval);
+ }
+
+ private void StopTimer()
+ {
+ _timer.Change(Timeout.Infinite, Timeout.Infinite);
+ }
+
+ #region Commanding
+
+ public Task<bool> VolumeDown(bool mute = false)
+ {
+ var sendVolume = (Volume - 5) > 0 ? Volume - 5 : 0;
+ if (mute && _muteVol == 0)
+ {
+ sendVolume = 0;
+ _muteVol = Volume;
+ }
+ return SetVolume(sendVolume);
+ }
+
+ public Task<bool> VolumeUp(bool unmute = false)
+ {
+ var sendVolume = (Volume + 5) < 100 ? Volume + 5 : 100;
+ if (unmute && _muteVol > 0)
+ sendVolume = _muteVol;
+ _muteVol = 0;
+ return SetVolume(sendVolume);
+ }
+
+ public Task ToggleMute()
+ {
+ if (_muteVol == 0)
+ {
+ _muteVol = Volume;
+ return SetVolume(0);
+ }
+
+ var tmp = _muteVol;
+ _muteVol = 0;
+ return SetVolume(tmp);
+ }
+
+ public async Task<bool> SetVolume(int value)
+ {
+ var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");
+ if (command == null)
+ return true;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, value))
+ .ConfigureAwait(false);
+ Volume = value;
+ return true;
+ }
+
+ public async Task<TimeSpan> Seek(TimeSpan value)
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek");
+ if (command == null)
+ return value;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, String.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
+ .ConfigureAwait(false);
+
+ return value;
+ }
+
+ public async Task<bool> SetAvTransport(string url, string header, string metaData)
+ {
+ StopTimer();
+
+ await SetStop().ConfigureAwait(false);
+ CurrentId = "0";
+
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI");
+ if (command == null)
+ return false;
+
+ var dictionary = new Dictionary<string, string>
+ {
+ {"CurrentURI", url},
+ {"CurrentURIMetaData", CreateDidlMeta(metaData)}
+ };
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, url, dictionary), header)
+ .ConfigureAwait(false);
+
+ if (!IsPlaying)
+ {
+ await Task.Delay(50).ConfigureAwait(false);
+ await SetPlay().ConfigureAwait(false);
+ }
+
+ _lapsCount = SetLapsCountToFull();
+ RestartTimer();
+
+ return true;
+ }
+
+ private string CreateDidlMeta(string value)
+ {
+ if (value == null)
+ return String.Empty;
+
+ var escapedData = value.Replace("<", "<").Replace(">", ">");
+
+ return String.Format(BaseDidl, escapedData.Replace("\r\n", ""));
+ }
+
+ private const string BaseDidl = "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">{0}</DIDL-Lite>";
+
+ public async Task<bool> SetNextAvTransport(string value, string header, string metaData)
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetNextAVTransportURI");
+ if (command == null)
+ return false;
+
+ var dictionary = new Dictionary<string, string>
+ {
+ {"NextURI", value},
+ {"NextURIMetaData", CreateDidlMeta(metaData)}
+ };
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, value, dictionary), header)
+ .ConfigureAwait(false);
+
+ await Task.Delay(100).ConfigureAwait(false);
+
+ return true;
+ }
+
+ public async Task<bool> SetPlay()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
+ if (command == null)
+ return false;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1))
+ .ConfigureAwait(false);
+
+ _lapsCount = SetLapsCountToFull();
+ return true;
+ }
+
+ public async Task<bool> SetStop()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
+ if (command == null)
+ return false;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1))
+ .ConfigureAwait(false);
+
+ await Task.Delay(50).ConfigureAwait(false);
+ return true;
+ }
+
+ public async Task<bool> SetPause()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
+ if (command == null)
+ return false;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 0))
+ .ConfigureAwait(false);
+
+ await Task.Delay(50).ConfigureAwait(false);
+ TransportState = "PAUSED_PLAYBACK";
+ return true;
+ }
+
+ #endregion
+
+ #region Get data
+
+ private int GetLapsCount()
+ {
+ // No need to get all data every lap, just every X time.
+ return 10;
+ }
+
+ int _lapsCount = 0;
+
+ private async void TimerCallback(object sender)
+ {
+ if (_disposed)
+ return;
+
+ StopTimer();
+
+ try
+ {
+ await GetTransportInfo().ConfigureAwait(false);
+
+ //If we're not playing anything no need to get additional data
+ if (TransportState != TRANSPORTSTATE.STOPPED)
+ {
+ var hasTrack = await GetPositionInfo().ConfigureAwait(false);
+
+ // TODO: Why make these requests if hasTrack==false?
+ // TODO ANSWER Some vendors don't include track in GetPositionInfo, use GetMediaInfo instead.
+ if (_lapsCount > GetLapsCount())
+ {
+ if (!hasTrack)
+ {
+ await GetMediaInfo().ConfigureAwait(false);
+ }
+ await GetVolume().ConfigureAwait(false);
+ _lapsCount = 0;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error updating device info", ex);
+ }
+
+ _lapsCount++;
+
+ if (_disposed)
+ return;
+
+ //If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive
+ if (TransportState != TRANSPORTSTATE.STOPPED)
+ RestartTimer();
+ else
+ RestartTimerInactive();
+ }
+
+ private async Task GetVolume()
+ {
+ var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
+ if (command == null)
+ return;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+ .ConfigureAwait(false);
+
+ if (result == null || result.Document == null)
+ return;
+
+ var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
+ var volumeValue = volume == null ? null : volume.Value;
+
+ if (volumeValue == null)
+ return;
+
+ Volume = Int32.Parse(volumeValue);
+
+ //Reset the Mute value if Volume is bigger than zero
+ if (Volume > 0 && _muteVol > 0)
+ {
+ _muteVol = 0;
+ }
+ }
+
+ private async Task GetTransportInfo()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
+ if (command == null)
+ return;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+ if (service == null)
+ return;
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+ .ConfigureAwait(false);
+
+ if (result == null || result.Document == null)
+ return;
+
+ var transportState =
+ result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
+
+ var transportStateValue = transportState == null ? null : transportState.Value;
+
+ if (transportStateValue != null)
+ TransportState = transportStateValue;
+
+ UpdateTime = DateTime.UtcNow;
+ }
+
+ private async Task GetMediaInfo()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
+ if (command == null)
+ return;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+ .ConfigureAwait(false);
+
+ if (result == null || result.Document == null)
+ return;
+
+ var track = result.Document.Descendants("CurrentURIMetaData").Select(i => i.Value).FirstOrDefault();
+
+ if (String.IsNullOrEmpty(track))
+ {
+ CurrentId = "0";
+ return;
+ }
+
+ var uPnpResponse = XElement.Parse(track);
+
+ var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse;
+
+ var uTrack = uParser.CreateObjectFromXML(new uParserObject
+ {
+ Type = e.GetValue(uPnpNamespaces.uClass),
+ Element = e
+ });
+
+ if (uTrack != null)
+ CurrentId = uTrack.Id;
+ }
+
+ private async Task<bool> GetPositionInfo()
+ {
+ var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
+ if (command == null)
+ return true;
+
+ var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+
+ if (service == null)
+ {
+ throw new InvalidOperationException("Unable to find service");
+ }
+
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+ .ConfigureAwait(false);
+
+ if (result == null || result.Document == null)
+ return true;
+
+ var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
+ var duration = durationElem == null ? null : durationElem.Value;
+
+ if (duration != null)
+ {
+ Duration = TimeSpan.Parse(duration);
+ }
+
+ var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null);
+ var position = positionElem == null ? null : positionElem.Value;
+
+ if (position != null)
+ {
+ Position = TimeSpan.Parse(position);
+ }
+
+ var track = result.Document.Descendants("TrackMetaData").Select(i => i.Value)
+ .FirstOrDefault();
+
+ if (String.IsNullOrEmpty(track))
+ {
+ //If track is null, some vendors do this, use GetMediaInfo instead
+ return false;
+ }
+
+ var uPnpResponse = XElement.Parse(track);
+
+ var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse;
+
+ var uTrack = uBaseObject.Create(e);
+
+ if (uTrack == null)
+ return true;
+
+ CurrentId = uTrack.Id;
+
+ return true;
+ }
+
+ #endregion
+
+ #region From XML
+
+ private async Task GetAVProtocolAsync()
+ {
+ var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
+ if (avService == null)
+ return;
+
+ var url = avService.SCPDURL;
+ if (!url.Contains("/"))
+ url = "/dmr/" + url;
+ if (!url.StartsWith("/"))
+ url = "/" + url;
+
+ var httpClient = new SsdpHttpClient(_httpClient);
+ var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
+
+ AvCommands = TransportCommands.Create(document);
+ }
+
+ private async Task GetRenderingProtocolAsync()
+ {
+ var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
+
+ if (avService == null)
+ return;
+ string url = avService.SCPDURL;
+ if (!url.Contains("/"))
+ url = "/dmr/" + url;
+ if (!url.StartsWith("/"))
+ url = "/" + url;
+
+ var httpClient = new SsdpHttpClient(_httpClient);
+ var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
+
+ RendererCommands = TransportCommands.Create(document);
+ }
+
+ internal TransportCommands AvCommands
+ {
+ get;
+ set;
+ }
+
+ internal TransportCommands RendererCommands
+ {
+ get;
+ set;
+ }
+
+ public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, ILogger logger)
+ {
+ var ssdpHttpClient = new SsdpHttpClient(httpClient);
+
+ var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false);
+
+ var deviceProperties = new DeviceProperties();
+
+ var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
+ if (name != null)
+ deviceProperties.Name = name.Value;
+
+ var name2 = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
+ if (name2 != null)
+ deviceProperties.Name = name2.Value;
+
+ var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
+ if (model != null)
+ deviceProperties.ModelName = model.Value;
+
+ var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
+ if (modelNumber != null)
+ deviceProperties.ModelNumber = modelNumber.Value;
+
+ var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
+ if (uuid != null)
+ deviceProperties.UUID = uuid.Value;
+
+ var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
+ if (manufacturer != null)
+ deviceProperties.Manufacturer = manufacturer.Value;
+
+ var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
+ if (manufacturerUrl != null)
+ deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
+
+ var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
+ if (presentationUrl != null)
+ deviceProperties.PresentationUrl = presentationUrl.Value;
+
+
+ deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
+
+ var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
+
+ if (icon != null)
+ {
+ deviceProperties.Icon = uIcon.Create(icon);
+ }
+
+ var isRenderer = false;
+
+ foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
+ {
+ if (services == null)
+ return null;
+
+ var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
+
+ if (servicesList == null)
+ return null;
+
+ foreach (var element in servicesList)
+ {
+ var service = uService.Create(element);
+
+ if (service != null)
+ {
+ deviceProperties.Services.Add(service);
+ if (service.ServiceId == ServiceAvtransportId)
+ {
+ isRenderer = true;
+ }
+ }
+ }
+ }
+
+ if (isRenderer)
+ {
+
+ var device = new Device(deviceProperties, httpClient, logger);
+
+ await device.GetRenderingProtocolAsync().ConfigureAwait(false);
+ await device.GetAVProtocolAsync().ConfigureAwait(false);
+
+ return device;
+ }
+
+ return null;
+ }
+
+ #endregion
+
+ #region Events
+
+ public event EventHandler<TransportStateEventArgs> PlaybackChanged;
+ public event EventHandler<CurrentIdEventArgs> CurrentIdChanged;
+
+ private void NotifyPlaybackChanged(bool value)
+ {
+ if (PlaybackChanged != null)
+ {
+ PlaybackChanged.Invoke(this, new TransportStateEventArgs
+ {
+ Stopped = IsStopped
+ });
+ }
+ }
+
+ private void NotifyCurrentIdChanged(string value)
+ {
+ if (CurrentIdChanged != null)
+ CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value));
+ }
+
+ #endregion
+
+ #region IDisposable
+
+ bool _disposed;
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+ _timer.Dispose();
+ }
+ }
+
+ #endregion
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
+ }
+
+ private class TRANSPORTSTATE
+ {
+ public const string STOPPED = "STOPPED";
+ public const string PLAYING = "PLAYING";
+ public const string TRANSITIONING = "TRANSITIONING";
+ public const string PAUSED_PLAYBACK = "PAUSED_PLAYBACK";
+ public const string PAUSED = "PAUSED";
+ }
+
+ }
+}
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index 48ef5e589..8bf9ec9f6 100644 --- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs +++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs @@ -1,481 +1,489 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Session; -using MediaBrowser.Dlna.PlayTo.Configuration; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Timers; -using Timer = System.Timers.Timer; - -namespace MediaBrowser.Dlna.PlayTo -{ - public class PlayToController : ISessionController, IDisposable - { - private Device _device; - private BaseItem _currentItem = null; - private TranscodeSettings[] _transcodeSettings; - private readonly SessionInfo _session; - private readonly ISessionManager _sessionManager; - private readonly IItemRepository _itemRepository; - private readonly ILibraryManager _libraryManager; - private readonly INetworkManager _networkManager; - private readonly ILogger _logger; - private bool _playbackStarted = false; - - public bool SupportsMediaRemoteControl - { - get { return true; } - } - - public bool IsSessionActive - { - get - { - if (_device == null || _device.UpdateTime == default(DateTime)) - return false; - - return DateTime.UtcNow <= _device.UpdateTime.AddSeconds(30); - } - } - - public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager) - { - _session = session; - _itemRepository = itemRepository; - _sessionManager = sessionManager; - _libraryManager = libraryManager; - _networkManager = networkManager; - _logger = logger; - } - - public void Init(Device device, TranscodeSettings[] transcodeSettings) - { - _transcodeSettings = transcodeSettings; - _device = device; - _device.PlaybackChanged += Device_PlaybackChanged; - _device.CurrentIdChanged += Device_CurrentIdChanged; - _device.Start(); - - _updateTimer = new Timer(1000); - _updateTimer.Elapsed += updateTimer_Elapsed; - _updateTimer.Start(); - } - - #region Device EventHandlers & Update Timer - - Timer _updateTimer; - - async void Device_PlaybackChanged(object sender, TransportStateEventArgs e) - { - if (_currentItem == null) - return; - - if (e.Stopped == false) - await ReportProgress().ConfigureAwait(false); - - else if (e.Stopped && _playbackStarted) - { - _playbackStarted = false; - - await _sessionManager.OnPlaybackStopped(new PlaybackStopInfo - { - Item = _currentItem, - SessionId = _session.Id, - PositionTicks = _device.Position.Ticks - - }).ConfigureAwait(false); - - await SetNext().ConfigureAwait(false); - } - } - - async void Device_CurrentIdChanged(object sender, CurrentIdEventArgs e) - { - if (e.Id != Guid.Empty) - { - if (_currentItem != null && _currentItem.Id == e.Id) - { - return; - } - - var item = _libraryManager.GetItemById(e.Id); - - if (item != null) - { - _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id); - _currentItem = item; - _playbackStarted = false; - - await ReportProgress().ConfigureAwait(false); - } - } - } - - /// <summary> - /// Handles the Elapsed event of the updateTimer control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="ElapsedEventArgs"/> instance containing the event data.</param> - async void updateTimer_Elapsed(object sender, ElapsedEventArgs e) - { - if (_disposed) - return; - - ((Timer)sender).Stop(); - - await ReportProgress().ConfigureAwait(false); - - if (!_disposed && IsSessionActive) - ((Timer)sender).Start(); - } - - /// <summary> - /// Reports the playback progress. - /// </summary> - /// <returns></returns> - private async Task ReportProgress() - { - if (_currentItem == null || _device.IsStopped) - return; - - if (!_playbackStarted) - { - await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false); - _playbackStarted = true; - } - - if ((_device.IsPlaying || _device.IsPaused)) - { - var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1); - if (playlistItem != null && playlistItem.Transcode) - { - await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo - { - Item = _currentItem, - SessionId = _session.Id, - PositionTicks = _device.Position.Ticks + playlistItem.StartPositionTicks, - IsMuted = _device.IsMuted, - IsPaused = _device.IsPaused - - }).ConfigureAwait(false); - } - else if (_currentItem != null) - { - await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo - { - Item = _currentItem, - SessionId = _session.Id, - PositionTicks = _device.Position.Ticks, - IsMuted = _device.IsMuted, - IsPaused = _device.IsPaused - - }).ConfigureAwait(false); - } - } - } - - #endregion - - #region SendCommands - - public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken) - { - _logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand); - - var items = new List<BaseItem>(); - foreach (string id in command.ItemIds) - { - AddItemFromId(Guid.Parse(id), items); - } - - var playlist = new List<PlaylistItem>(); - var isFirst = true; - - var serverAddress = GetServerAddress(); - - foreach (var item in items) - { - if (isFirst && command.StartPositionTicks.HasValue) - { - playlist.Add(CreatePlaylistItem(item, command.StartPositionTicks.Value, serverAddress)); - isFirst = false; - } - else - { - playlist.Add(CreatePlaylistItem(item, 0, serverAddress)); - } - } - - _logger.Debug("{0} - Playlist created", _session.DeviceName); - - if (command.PlayCommand == PlayCommand.PlayLast) - { - AddItemsToPlaylist(playlist); - return Task.FromResult(true); - } - if (command.PlayCommand == PlayCommand.PlayNext) - { - AddItemsToPlaylist(playlist); - return Task.FromResult(true); - } - - _logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count); - return PlayItems(playlist); - } - - public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken) - { - switch (command.Command) - { - case PlaystateCommand.Stop: - Playlist.Clear(); - return _device.SetStop(); - - case PlaystateCommand.Pause: - return _device.SetPause(); - - case PlaystateCommand.Unpause: - return _device.SetPlay(); - - case PlaystateCommand.Seek: - var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1); - if (playlistItem != null && playlistItem.Transcode && playlistItem.IsVideo && _currentItem != null) - { - var newItem = CreatePlaylistItem(_currentItem, command.SeekPositionTicks ?? 0, GetServerAddress()); - playlistItem.StartPositionTicks = newItem.StartPositionTicks; - playlistItem.StreamUrl = newItem.StreamUrl; - playlistItem.Didl = newItem.Didl; - return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl); - - } - return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0)); - - - case PlaystateCommand.NextTrack: - _currentItem = null; - return SetNext(); - - case PlaystateCommand.PreviousTrack: - _currentItem = null; - return SetPrevious(); - } - - return Task.FromResult(true); - } - - public Task SendSystemCommand(SystemCommand command, CancellationToken cancellationToken) - { - switch (command) - { - case SystemCommand.VolumeDown: - return _device.VolumeDown(); - case SystemCommand.VolumeUp: - return _device.VolumeUp(); - case SystemCommand.Mute: - return _device.VolumeDown(true); - case SystemCommand.Unmute: - return _device.VolumeUp(true); - case SystemCommand.ToggleMute: - return _device.ToggleMute(); - default: - return Task.FromResult(true); - } - } - - public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendRestartRequiredNotification(CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendServerRestartNotification(CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendServerShutdownNotification(CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendBrowseCommand(BrowseRequest command, CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public Task SendMessageCommand(MessageCommand command, CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - #endregion - - #region Playlist - - private List<PlaylistItem> _playlist = new List<PlaylistItem>(); - - private List<PlaylistItem> Playlist - { - get - { - return _playlist; - } - set - { - _playlist = value; - } - } - - private void AddItemFromId(Guid id, List<BaseItem> list) - { - var item = _libraryManager.GetItemById(id); - if (item.IsFolder) - { - foreach (var childId in _itemRepository.GetChildren(item.Id)) - { - AddItemFromId(childId, list); - } - } - else - { - if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video) - { - list.Add(item); - } - } - } - - private string GetServerAddress() - { - return string.Format("{0}://{1}:{2}/mediabrowser", - - "http", - _networkManager.GetLocalIpAddresses().FirstOrDefault() ?? "localhost", - "8096" - ); - } - - private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress) - { - var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList(); - - var playlistItem = PlaylistItem.GetBasicConfig(item, _transcodeSettings); - playlistItem.StartPositionTicks = startPostionTicks; - - if (playlistItem.IsAudio) - playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress); - else - { - playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress); - } - - var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams); - playlistItem.Didl = didl; - - var header = StreamHelper.GetDlnaHeaders(playlistItem); - playlistItem.DlnaHeaders = header; - return playlistItem; - } - - /// <summary> - /// Plays the items. - /// </summary> - /// <param name="items">The items.</param> - /// <returns></returns> - private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items) - { - Playlist.Clear(); - Playlist.AddRange(items); - await SetNext(); - return true; - } - - /// <summary> - /// Adds the items to playlist. - /// </summary> - /// <param name="items">The items.</param> - private void AddItemsToPlaylist(IEnumerable<PlaylistItem> items) - { - Playlist.AddRange(items); - } - - private async Task<bool> SetNext() - { - if (!Playlist.Any() || Playlist.All(i => i.PlayState != 0)) - { - return true; - } - var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1); - - if (currentitem != null) - { - currentitem.PlayState = 2; - } - - var nextTrack = Playlist.FirstOrDefault(i => i.PlayState == 0); - if (nextTrack == null) - { - await _device.SetStop(); - return true; - } - nextTrack.PlayState = 1; - await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl); - if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode) - await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks)); - return true; - } - - public Task<bool> SetPrevious() - { - if (!Playlist.Any() || Playlist.All(i => i.PlayState != 2)) - return Task.FromResult(false); - - var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1); - - var prevTrack = Playlist.LastOrDefault(i => i.PlayState == 2); - - if (currentitem != null) - { - currentitem.PlayState = 0; - } - - if (prevTrack == null) - return Task.FromResult(false); - - prevTrack.PlayState = 1; - return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl); - } - - #endregion - - private bool _disposed; - - public void Dispose() - { - if (!_disposed) - { - _updateTimer.Stop(); - _disposed = true; - _device.Dispose(); - _logger.Log(LogSeverity.Debug, "PlayTo - Controller disposed"); - } - } - } -} +using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Dlna.PlayTo.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Session;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Timers;
+using Timer = System.Timers.Timer;
+
+namespace MediaBrowser.Dlna.PlayTo
+{
+ public class PlayToController : ISessionController, IDisposable
+ {
+ private Device _device;
+ private BaseItem _currentItem = null;
+ private TranscodeSettings[] _transcodeSettings;
+ private readonly SessionInfo _session;
+ private readonly ISessionManager _sessionManager;
+ private readonly IItemRepository _itemRepository;
+ private readonly ILibraryManager _libraryManager;
+ private readonly INetworkManager _networkManager;
+ private readonly ILogger _logger;
+ private bool _playbackStarted = false;
+
+ public bool SupportsMediaRemoteControl
+ {
+ get { return true; }
+ }
+
+ public bool IsSessionActive
+ {
+ get
+ {
+ if (_device == null || _device.UpdateTime == default(DateTime))
+ return false;
+
+ return DateTime.UtcNow <= _device.UpdateTime.AddSeconds(30);
+ }
+ }
+
+ public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager)
+ {
+ _session = session;
+ _itemRepository = itemRepository;
+ _sessionManager = sessionManager;
+ _libraryManager = libraryManager;
+ _networkManager = networkManager;
+ _logger = logger;
+ }
+
+ public void Init(Device device, TranscodeSettings[] transcodeSettings)
+ {
+ _transcodeSettings = transcodeSettings;
+ _device = device;
+ _device.PlaybackChanged += Device_PlaybackChanged;
+ _device.CurrentIdChanged += Device_CurrentIdChanged;
+ _device.Start();
+
+ _updateTimer = new Timer(1000);
+ _updateTimer.Elapsed += updateTimer_Elapsed;
+ _updateTimer.Start();
+ }
+
+ #region Device EventHandlers & Update Timer
+
+ Timer _updateTimer;
+
+ async void Device_PlaybackChanged(object sender, TransportStateEventArgs e)
+ {
+ if (_currentItem == null)
+ return;
+
+ if (e.Stopped == false)
+ await ReportProgress().ConfigureAwait(false);
+
+ else if (e.Stopped && _playbackStarted)
+ {
+ _playbackStarted = false;
+
+ await _sessionManager.OnPlaybackStopped(new PlaybackStopInfo
+ {
+ Item = _currentItem,
+ SessionId = _session.Id,
+ PositionTicks = _device.Position.Ticks
+
+ }).ConfigureAwait(false);
+
+ await SetNext().ConfigureAwait(false);
+ }
+ }
+
+ async void Device_CurrentIdChanged(object sender, CurrentIdEventArgs e)
+ {
+ if (e.Id != Guid.Empty)
+ {
+ if (_currentItem != null && _currentItem.Id == e.Id)
+ {
+ return;
+ }
+
+ var item = _libraryManager.GetItemById(e.Id);
+
+ if (item != null)
+ {
+ _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id);
+ _currentItem = item;
+ _playbackStarted = false;
+
+ await ReportProgress().ConfigureAwait(false);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Handles the Elapsed event of the updateTimer control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="ElapsedEventArgs"/> instance containing the event data.</param>
+ async void updateTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ if (_disposed)
+ return;
+
+ ((Timer)sender).Stop();
+
+
+ if(!IsSessionActive)
+ {
+ //Session is inactive, mark it for Disposal and don't start the elapsed timer.
+ await _sessionManager.ReportSessionEnded(this._session.Id);
+ return;
+ }
+
+ await ReportProgress().ConfigureAwait(false);
+
+ if (!_disposed && IsSessionActive)
+ ((Timer)sender).Start();
+ }
+
+ /// <summary>
+ /// Reports the playback progress.
+ /// </summary>
+ /// <returns></returns>
+ private async Task ReportProgress()
+ {
+ if (_currentItem == null || _device.IsStopped)
+ return;
+
+ if (!_playbackStarted)
+ {
+ await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false);
+ _playbackStarted = true;
+ }
+
+ if ((_device.IsPlaying || _device.IsPaused))
+ {
+ var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1);
+ if (playlistItem != null && playlistItem.Transcode)
+ {
+ await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo
+ {
+ Item = _currentItem,
+ SessionId = _session.Id,
+ PositionTicks = _device.Position.Ticks + playlistItem.StartPositionTicks,
+ IsMuted = _device.IsMuted,
+ IsPaused = _device.IsPaused
+
+ }).ConfigureAwait(false);
+ }
+ else if (_currentItem != null)
+ {
+ await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo
+ {
+ Item = _currentItem,
+ SessionId = _session.Id,
+ PositionTicks = _device.Position.Ticks,
+ IsMuted = _device.IsMuted,
+ IsPaused = _device.IsPaused
+
+ }).ConfigureAwait(false);
+ }
+ }
+ }
+
+ #endregion
+
+ #region SendCommands
+
+ public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
+ {
+ _logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand);
+
+ var items = new List<BaseItem>();
+ foreach (string id in command.ItemIds)
+ {
+ AddItemFromId(Guid.Parse(id), items);
+ }
+
+ var playlist = new List<PlaylistItem>();
+ var isFirst = true;
+
+ var serverAddress = GetServerAddress();
+
+ foreach (var item in items)
+ {
+ if (isFirst && command.StartPositionTicks.HasValue)
+ {
+ playlist.Add(CreatePlaylistItem(item, command.StartPositionTicks.Value, serverAddress));
+ isFirst = false;
+ }
+ else
+ {
+ playlist.Add(CreatePlaylistItem(item, 0, serverAddress));
+ }
+ }
+
+ _logger.Debug("{0} - Playlist created", _session.DeviceName);
+
+ if (command.PlayCommand == PlayCommand.PlayLast)
+ {
+ AddItemsToPlaylist(playlist);
+ return Task.FromResult(true);
+ }
+ if (command.PlayCommand == PlayCommand.PlayNext)
+ {
+ AddItemsToPlaylist(playlist);
+ return Task.FromResult(true);
+ }
+
+ _logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count);
+ return PlayItems(playlist);
+ }
+
+ public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
+ {
+ switch (command.Command)
+ {
+ case PlaystateCommand.Stop:
+ Playlist.Clear();
+ return _device.SetStop();
+
+ case PlaystateCommand.Pause:
+ return _device.SetPause();
+
+ case PlaystateCommand.Unpause:
+ return _device.SetPlay();
+
+ case PlaystateCommand.Seek:
+ var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1);
+ if (playlistItem != null && playlistItem.Transcode && playlistItem.IsVideo && _currentItem != null)
+ {
+ var newItem = CreatePlaylistItem(_currentItem, command.SeekPositionTicks ?? 0, GetServerAddress());
+ playlistItem.StartPositionTicks = newItem.StartPositionTicks;
+ playlistItem.StreamUrl = newItem.StreamUrl;
+ playlistItem.Didl = newItem.Didl;
+ return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl);
+
+ }
+ return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0));
+
+
+ case PlaystateCommand.NextTrack:
+ _currentItem = null;
+ return SetNext();
+
+ case PlaystateCommand.PreviousTrack:
+ _currentItem = null;
+ return SetPrevious();
+ }
+
+ return Task.FromResult(true);
+ }
+
+ public Task SendSystemCommand(SystemCommand command, CancellationToken cancellationToken)
+ {
+ switch (command)
+ {
+ case SystemCommand.VolumeDown:
+ return _device.VolumeDown();
+ case SystemCommand.VolumeUp:
+ return _device.VolumeUp();
+ case SystemCommand.Mute:
+ return _device.VolumeDown(true);
+ case SystemCommand.Unmute:
+ return _device.VolumeUp(true);
+ case SystemCommand.ToggleMute:
+ return _device.ToggleMute();
+ default:
+ return Task.FromResult(true);
+ }
+ }
+
+ public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendServerRestartNotification(CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendServerShutdownNotification(CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendBrowseCommand(BrowseRequest command, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public Task SendMessageCommand(MessageCommand command, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ #endregion
+
+ #region Playlist
+
+ private List<PlaylistItem> _playlist = new List<PlaylistItem>();
+
+ private List<PlaylistItem> Playlist
+ {
+ get
+ {
+ return _playlist;
+ }
+ set
+ {
+ _playlist = value;
+ }
+ }
+
+ private void AddItemFromId(Guid id, List<BaseItem> list)
+ {
+ var item = _libraryManager.GetItemById(id);
+ if (item.IsFolder)
+ {
+ foreach (var childId in _itemRepository.GetChildren(item.Id))
+ {
+ AddItemFromId(childId, list);
+ }
+ }
+ else
+ {
+ if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video)
+ {
+ list.Add(item);
+ }
+ }
+ }
+
+ private string GetServerAddress()
+ {
+ return string.Format("{0}://{1}:{2}/mediabrowser",
+
+ "http",
+ _networkManager.GetLocalIpAddresses().FirstOrDefault() ?? "localhost",
+ "8096"
+ );
+ }
+
+ private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
+ {
+ var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList();
+
+ var playlistItem = PlaylistItem.GetBasicConfig(item, _transcodeSettings);
+ playlistItem.StartPositionTicks = startPostionTicks;
+
+ if (playlistItem.IsAudio)
+ playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
+ else
+ {
+ playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
+ }
+
+ var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
+ playlistItem.Didl = didl;
+
+ var header = StreamHelper.GetDlnaHeaders(playlistItem);
+ playlistItem.DlnaHeaders = header;
+ return playlistItem;
+ }
+
+ /// <summary>
+ /// Plays the items.
+ /// </summary>
+ /// <param name="items">The items.</param>
+ /// <returns></returns>
+ private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items)
+ {
+ Playlist.Clear();
+ Playlist.AddRange(items);
+ await SetNext();
+ return true;
+ }
+
+ /// <summary>
+ /// Adds the items to playlist.
+ /// </summary>
+ /// <param name="items">The items.</param>
+ private void AddItemsToPlaylist(IEnumerable<PlaylistItem> items)
+ {
+ Playlist.AddRange(items);
+ }
+
+ private async Task<bool> SetNext()
+ {
+ if (!Playlist.Any() || Playlist.All(i => i.PlayState != 0))
+ {
+ return true;
+ }
+ var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1);
+
+ if (currentitem != null)
+ {
+ currentitem.PlayState = 2;
+ }
+
+ var nextTrack = Playlist.FirstOrDefault(i => i.PlayState == 0);
+ if (nextTrack == null)
+ {
+ await _device.SetStop();
+ return true;
+ }
+ nextTrack.PlayState = 1;
+ await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl);
+ if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
+ await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
+ return true;
+ }
+
+ public Task<bool> SetPrevious()
+ {
+ if (!Playlist.Any() || Playlist.All(i => i.PlayState != 2))
+ return Task.FromResult(false);
+
+ var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1);
+
+ var prevTrack = Playlist.LastOrDefault(i => i.PlayState == 2);
+
+ if (currentitem != null)
+ {
+ currentitem.PlayState = 0;
+ }
+
+ if (prevTrack == null)
+ return Task.FromResult(false);
+
+ prevTrack.PlayState = 1;
+ return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl);
+ }
+
+ #endregion
+
+ private bool _disposed;
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _updateTimer.Stop();
+ _disposed = true;
+ _device.Dispose();
+ _logger.Log(LogSeverity.Debug, "PlayTo - Controller disposed");
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 7ac158065..594179fd9 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -1,257 +1,256 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E64C-2A6F-4E35-9533-D53AC07C2CD1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C5D6ABC-D277-407B-8061-3AA04251D539}" - ProjectSection(SolutionItems) = preProject - Performance19.psess = Performance19.psess - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model.net35", "MediaBrowser.Model.net35\MediaBrowser.Model.net35.csproj", "{657B5410-7C3B-4806-9753-D254102CE537}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Tests", "MediaBrowser.Tests\MediaBrowser.Tests.csproj", "{E22BFD35-0FCD-4A85-978A-C22DCD73A081}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model.Portable", "MediaBrowser.Model.Portable\MediaBrowser.Model.Portable.csproj", "{D729ADB1-1C01-428D-B680-8EFACD687B2A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplication", "MediaBrowser.ServerApplication\MediaBrowser.ServerApplication.csproj", "{94ADE4D3-B7EC-45CD-A200-CC469433072B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Win32.ActiveCfg = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x64.ActiveCfg = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.ActiveCfg = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.Build.0 = Debug|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.Build.0 = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Win32.ActiveCfg = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x64.ActiveCfg = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.ActiveCfg = Release|Any CPU - {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.Build.0 = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Win32.ActiveCfg = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x64.ActiveCfg = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.ActiveCfg = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.Build.0 = Debug|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.Build.0 = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Win32.ActiveCfg = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x64.ActiveCfg = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.ActiveCfg = Release|Any CPU - {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.Build.0 = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Win32.ActiveCfg = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x64.ActiveCfg = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.ActiveCfg = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.Build.0 = Debug|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.Build.0 = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Win32.ActiveCfg = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x64.ActiveCfg = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.ActiveCfg = Release|Any CPU - {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.Build.0 = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Win32.ActiveCfg = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x64.ActiveCfg = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.ActiveCfg = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.Build.0 = Debug|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.Build.0 = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Win32.ActiveCfg = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x64.ActiveCfg = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.ActiveCfg = Release|Any CPU - {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.Build.0 = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Win32.ActiveCfg = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x64.ActiveCfg = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.ActiveCfg = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.Build.0 = Debug|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Any CPU.Build.0 = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Win32.ActiveCfg = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x64.ActiveCfg = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU - {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Win32.ActiveCfg = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x64.ActiveCfg = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.Build.0 = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Win32.ActiveCfg = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x64.ActiveCfg = Release|Any CPU - {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Win32.ActiveCfg = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x64.ActiveCfg = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Win32.ActiveCfg = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x64.ActiveCfg = Release|Any CPU - {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Any CPU.Build.0 = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Win32.ActiveCfg = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|x64.ActiveCfg = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Debug|x86.ActiveCfg = Debug|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|Any CPU.ActiveCfg = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|Any CPU.Build.0 = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|Win32.ActiveCfg = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|x64.ActiveCfg = Release|Any CPU - {657B5410-7C3B-4806-9753-D254102CE537}.Release|x86.ActiveCfg = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Win32.ActiveCfg = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|x64.ActiveCfg = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|x86.ActiveCfg = Debug|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Any CPU.Build.0 = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Win32.ActiveCfg = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|x64.ActiveCfg = Release|Any CPU - {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|x86.ActiveCfg = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Win32.ActiveCfg = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x64.ActiveCfg = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.ActiveCfg = Debug|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.Build.0 = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Win32.ActiveCfg = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x64.ActiveCfg = Release|Any CPU - {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.ActiveCfg = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Win32.ActiveCfg = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|x64.ActiveCfg = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|x86.ActiveCfg = Debug|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Any CPU.Build.0 = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Win32.ActiveCfg = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|x64.ActiveCfg = Release|Any CPU - {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|x86.ActiveCfg = Release|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Any CPU.ActiveCfg = Debug|x86 - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Any CPU.Build.0 = Debug|x86 - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Win32.ActiveCfg = Debug|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|x64.ActiveCfg = Debug|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|x86.ActiveCfg = Debug|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Any CPU.ActiveCfg = Release|x86 - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Any CPU.Build.0 = Release|x86 - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Win32.ActiveCfg = Release|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x64.ActiveCfg = Release|Any CPU - {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x86.ActiveCfg = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Win32.ActiveCfg = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x64.ActiveCfg = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x86.ActiveCfg = Debug|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.Build.0 = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Win32.ActiveCfg = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x64.ActiveCfg = Release|Any CPU - {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection -EndGlobal +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E64C-2A6F-4E35-9533-D53AC07C2CD1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C5D6ABC-D277-407B-8061-3AA04251D539}"
+ ProjectSection(SolutionItems) = preProject
+ Performance19.psess = Performance19.psess
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}"
+ ProjectSection(SolutionItems) = preProject
+ .nuget\NuGet.Config = .nuget\NuGet.Config
+ .nuget\NuGet.exe = .nuget\NuGet.exe
+ .nuget\NuGet.targets = .nuget\NuGet.targets
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model.net35", "MediaBrowser.Model.net35\MediaBrowser.Model.net35.csproj", "{657B5410-7C3B-4806-9753-D254102CE537}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Tests", "MediaBrowser.Tests\MediaBrowser.Tests.csproj", "{E22BFD35-0FCD-4A85-978A-C22DCD73A081}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model.Portable", "MediaBrowser.Model.Portable\MediaBrowser.Model.Portable.csproj", "{D729ADB1-1C01-428D-B680-8EFACD687B2A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplication", "MediaBrowser.ServerApplication\MediaBrowser.ServerApplication.csproj", "{94ADE4D3-B7EC-45CD-A200-CC469433072B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.Build.0 = Debug|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Win32.ActiveCfg = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x64.ActiveCfg = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.ActiveCfg = Release|Any CPU
+ {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.Build.0 = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.Build.0 = Debug|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Win32.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x64.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.ActiveCfg = Release|Any CPU
+ {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.Build.0 = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.Build.0 = Debug|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Win32.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x64.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.ActiveCfg = Release|Any CPU
+ {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.Build.0 = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.Build.0 = Debug|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Win32.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x64.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.ActiveCfg = Release|Any CPU
+ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.Build.0 = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.Build.0 = Debug|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|Win32.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x64.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU
+ {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Win32.ActiveCfg = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x64.ActiveCfg = Release|Any CPU
+ {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Win32.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x64.ActiveCfg = Release|Any CPU
+ {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|Any CPU.Build.0 = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|Win32.ActiveCfg = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|x64.ActiveCfg = Release|Any CPU
+ {657B5410-7C3B-4806-9753-D254102CE537}.Release|x86.ActiveCfg = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|x64.ActiveCfg = Release|Any CPU
+ {E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Release|x86.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Win32.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x64.ActiveCfg = Release|Any CPU
+ {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.ActiveCfg = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|Win32.ActiveCfg = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|x64.ActiveCfg = Release|Any CPU
+ {D729ADB1-1C01-428D-B680-8EFACD687B2A}.Release|x86.ActiveCfg = Release|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Any CPU.Build.0 = Debug|x86
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Any CPU.ActiveCfg = Release|x86
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Any CPU.Build.0 = Release|x86
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Win32.ActiveCfg = Release|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x64.ActiveCfg = Release|Any CPU
+ {94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x86.ActiveCfg = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Win32.ActiveCfg = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x64.ActiveCfg = Release|Any CPU
+ {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
|
