diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs
index 6b5e8de9f8..dd416b5a44 100644
--- a/MediaBrowser.Dlna/PlayTo/Device.cs
+++ b/MediaBrowser.Dlna/PlayTo/Device.cs
@@ -1,790 +1,751 @@
-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);
- }
-
-
- ///
- /// Restarts the timer in inactive mode.
- ///
- private void RestartTimerInactive()
- {
- var interval = GetInactiveTimerIntervalMs();
-
- _timer.Change(interval, interval);
- }
-
- private void StopTimer()
- {
- _timer.Change(Timeout.Infinite, Timeout.Infinite);
- }
-
- #region Commanding
-
- public Task 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 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 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 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 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
- {
- {"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 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
- {
- {"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 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 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 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 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 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 PlaybackChanged;
- public event EventHandler 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";
- }
-
- }
-}
+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 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 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 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 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 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
+ {
+ {"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 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
+ {
+ {"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 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 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 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 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 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 PlaybackChanged;
+ public event EventHandler 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);
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
index 8bf9ec9f6a..48ef5e5897 100644
--- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs
+++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
@@ -1,489 +1,481 @@
-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);
- }
- }
- }
-
- ///
- /// Handles the Elapsed event of the updateTimer control.
- ///
- /// The source of the event.
- /// The instance containing the event data.
- 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();
- }
-
- ///
- /// Reports the playback progress.
- ///
- ///
- 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 { "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();
- foreach (string id in command.ItemIds)
- {
- AddItemFromId(Guid.Parse(id), items);
- }
-
- var playlist = new List();
- 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 _playlist = new List();
-
- private List Playlist
- {
- get
- {
- return _playlist;
- }
- set
- {
- _playlist = value;
- }
- }
-
- private void AddItemFromId(Guid id, List 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;
- }
-
- ///
- /// Plays the items.
- ///
- /// The items.
- ///
- private async Task PlayItems(IEnumerable items)
- {
- Playlist.Clear();
- Playlist.AddRange(items);
- await SetNext();
- return true;
- }
-
- ///
- /// Adds the items to playlist.
- ///
- /// The items.
- private void AddItemsToPlaylist(IEnumerable items)
- {
- Playlist.AddRange(items);
- }
-
- private async Task 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 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);
+ }
+ }
+ }
+
+ ///
+ /// Handles the Elapsed event of the updateTimer control.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ async void updateTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ if (_disposed)
+ return;
+
+ ((Timer)sender).Stop();
+
+ await ReportProgress().ConfigureAwait(false);
+
+ if (!_disposed && IsSessionActive)
+ ((Timer)sender).Start();
+ }
+
+ ///
+ /// Reports the playback progress.
+ ///
+ ///
+ 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 { "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();
+ foreach (string id in command.ItemIds)
+ {
+ AddItemFromId(Guid.Parse(id), items);
+ }
+
+ var playlist = new List();
+ 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 _playlist = new List();
+
+ private List Playlist
+ {
+ get
+ {
+ return _playlist;
+ }
+ set
+ {
+ _playlist = value;
+ }
+ }
+
+ private void AddItemFromId(Guid id, List 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;
+ }
+
+ ///
+ /// Plays the items.
+ ///
+ /// The items.
+ ///
+ private async Task PlayItems(IEnumerable items)
+ {
+ Playlist.Clear();
+ Playlist.AddRange(items);
+ await SetNext();
+ return true;
+ }
+
+ ///
+ /// Adds the items to playlist.
+ ///
+ /// The items.
+ private void AddItemsToPlaylist(IEnumerable items)
+ {
+ Playlist.AddRange(items);
+ }
+
+ private async Task 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 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 594179fd9e..7ac1580659 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -1,256 +1,257 @@
-
-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
+
+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