diff options
| author | 7illusions <z@7illusions.com> | 2014-03-10 11:10:16 +0100 |
|---|---|---|
| committer | 7illusions <z@7illusions.com> | 2014-03-10 11:10:16 +0100 |
| commit | d6d1c3839a47c93fd6950971611710ec93334f4f (patch) | |
| tree | 21e91fb006384f1f3d1d42c0fa91f53726a9055f | |
| parent | 6bbf2d115e3c2a5c570da8b1fe4cc8cc8ef2d681 (diff) | |
Revert "Improved polling and Session handling"
This reverts commit 5a1bdc578bf8440cf5ea59555f6ad3ca707768e3.
| -rw-r--r-- | MediaBrowser.Dlna/PlayTo/Device.cs | 1541 | ||||
| -rw-r--r-- | MediaBrowser.Dlna/PlayTo/DlnaController.cs | 970 | ||||
| -rw-r--r-- | MediaBrowser.sln | 513 |
3 files changed, 1489 insertions, 1535 deletions
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index 6b5e8de9f..dd416b5a4 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);
- }
-
-
- /// <summary>
- /// Restarts the timer in inactive mode.
- /// </summary>
- private void RestartTimerInactive()
- {
- var interval = GetInactiveTimerIntervalMs();
-
- _timer.Change(interval, interval);
- }
-
- private void StopTimer()
- {
- _timer.Change(Timeout.Infinite, Timeout.Infinite);
- }
-
- #region Commanding
-
- public Task<bool> VolumeDown(bool mute = false)
- {
- var sendVolume = (Volume - 5) > 0 ? Volume - 5 : 0;
- if (mute && _muteVol == 0)
- {
- sendVolume = 0;
- _muteVol = Volume;
- }
- return SetVolume(sendVolume);
- }
-
- public Task<bool> VolumeUp(bool unmute = false)
- {
- var sendVolume = (Volume + 5) < 100 ? Volume + 5 : 100;
- if (unmute && _muteVol > 0)
- sendVolume = _muteVol;
- _muteVol = 0;
- return SetVolume(sendVolume);
- }
-
- public Task ToggleMute()
- {
- if (_muteVol == 0)
- {
- _muteVol = Volume;
- return SetVolume(0);
- }
-
- var tmp = _muteVol;
- _muteVol = 0;
- return SetVolume(tmp);
- }
-
- public async Task<bool> SetVolume(int value)
- {
- var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");
- if (command == null)
- return true;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, value))
- .ConfigureAwait(false);
- Volume = value;
- return true;
- }
-
- public async Task<TimeSpan> Seek(TimeSpan value)
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek");
- if (command == null)
- return value;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, String.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
- .ConfigureAwait(false);
-
- return value;
- }
-
- public async Task<bool> SetAvTransport(string url, string header, string metaData)
- {
- StopTimer();
-
- await SetStop().ConfigureAwait(false);
- CurrentId = "0";
-
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI");
- if (command == null)
- return false;
-
- var dictionary = new Dictionary<string, string>
- {
- {"CurrentURI", url},
- {"CurrentURIMetaData", CreateDidlMeta(metaData)}
- };
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, url, dictionary), header)
- .ConfigureAwait(false);
-
- if (!IsPlaying)
- {
- await Task.Delay(50).ConfigureAwait(false);
- await SetPlay().ConfigureAwait(false);
- }
-
- _lapsCount = SetLapsCountToFull();
- RestartTimer();
-
- return true;
- }
-
- private string CreateDidlMeta(string value)
- {
- if (value == null)
- return String.Empty;
-
- var escapedData = value.Replace("<", "<").Replace(">", ">");
-
- return String.Format(BaseDidl, escapedData.Replace("\r\n", ""));
- }
-
- private const string BaseDidl = "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">{0}</DIDL-Lite>";
-
- public async Task<bool> SetNextAvTransport(string value, string header, string metaData)
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetNextAVTransportURI");
- if (command == null)
- return false;
-
- var dictionary = new Dictionary<string, string>
- {
- {"NextURI", value},
- {"NextURIMetaData", CreateDidlMeta(metaData)}
- };
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, value, dictionary), header)
- .ConfigureAwait(false);
-
- await Task.Delay(100).ConfigureAwait(false);
-
- return true;
- }
-
- public async Task<bool> SetPlay()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
- if (command == null)
- return false;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1))
- .ConfigureAwait(false);
-
- _lapsCount = SetLapsCountToFull();
- return true;
- }
-
- public async Task<bool> SetStop()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
- if (command == null)
- return false;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1))
- .ConfigureAwait(false);
-
- await Task.Delay(50).ConfigureAwait(false);
- return true;
- }
-
- public async Task<bool> SetPause()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
- if (command == null)
- return false;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 0))
- .ConfigureAwait(false);
-
- await Task.Delay(50).ConfigureAwait(false);
- TransportState = "PAUSED_PLAYBACK";
- return true;
- }
-
- #endregion
-
- #region Get data
-
- private int GetLapsCount()
- {
- // No need to get all data every lap, just every X time.
- return 10;
- }
-
- int _lapsCount = 0;
-
- private async void TimerCallback(object sender)
- {
- if (_disposed)
- return;
-
- StopTimer();
-
- try
- {
- await GetTransportInfo().ConfigureAwait(false);
-
- //If we're not playing anything no need to get additional data
- if (TransportState != TRANSPORTSTATE.STOPPED)
- {
- var hasTrack = await GetPositionInfo().ConfigureAwait(false);
-
- // TODO: Why make these requests if hasTrack==false?
- // TODO ANSWER Some vendors don't include track in GetPositionInfo, use GetMediaInfo instead.
- if (_lapsCount > GetLapsCount())
- {
- if (!hasTrack)
- {
- await GetMediaInfo().ConfigureAwait(false);
- }
- await GetVolume().ConfigureAwait(false);
- _lapsCount = 0;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error updating device info", ex);
- }
-
- _lapsCount++;
-
- if (_disposed)
- return;
-
- //If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive
- if (TransportState != TRANSPORTSTATE.STOPPED)
- RestartTimer();
- else
- RestartTimerInactive();
- }
-
- private async Task GetVolume()
- {
- var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
- if (command == null)
- return;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
- .ConfigureAwait(false);
-
- if (result == null || result.Document == null)
- return;
-
- var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
- var volumeValue = volume == null ? null : volume.Value;
-
- if (volumeValue == null)
- return;
-
- Volume = Int32.Parse(volumeValue);
-
- //Reset the Mute value if Volume is bigger than zero
- if (Volume > 0 && _muteVol > 0)
- {
- _muteVol = 0;
- }
- }
-
- private async Task GetTransportInfo()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
- if (command == null)
- return;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
- if (service == null)
- return;
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
- .ConfigureAwait(false);
-
- if (result == null || result.Document == null)
- return;
-
- var transportState =
- result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
-
- var transportStateValue = transportState == null ? null : transportState.Value;
-
- if (transportStateValue != null)
- TransportState = transportStateValue;
-
- UpdateTime = DateTime.UtcNow;
- }
-
- private async Task GetMediaInfo()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
- if (command == null)
- return;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
- .ConfigureAwait(false);
-
- if (result == null || result.Document == null)
- return;
-
- var track = result.Document.Descendants("CurrentURIMetaData").Select(i => i.Value).FirstOrDefault();
-
- if (String.IsNullOrEmpty(track))
- {
- CurrentId = "0";
- return;
- }
-
- var uPnpResponse = XElement.Parse(track);
-
- var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse;
-
- var uTrack = uParser.CreateObjectFromXML(new uParserObject
- {
- Type = e.GetValue(uPnpNamespaces.uClass),
- Element = e
- });
-
- if (uTrack != null)
- CurrentId = uTrack.Id;
- }
-
- private async Task<bool> GetPositionInfo()
- {
- var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
- if (command == null)
- return true;
-
- var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
-
- if (service == null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
- .ConfigureAwait(false);
-
- if (result == null || result.Document == null)
- return true;
-
- var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
- var duration = durationElem == null ? null : durationElem.Value;
-
- if (duration != null)
- {
- Duration = TimeSpan.Parse(duration);
- }
-
- var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null);
- var position = positionElem == null ? null : positionElem.Value;
-
- if (position != null)
- {
- Position = TimeSpan.Parse(position);
- }
-
- var track = result.Document.Descendants("TrackMetaData").Select(i => i.Value)
- .FirstOrDefault();
-
- if (String.IsNullOrEmpty(track))
- {
- //If track is null, some vendors do this, use GetMediaInfo instead
- return false;
- }
-
- var uPnpResponse = XElement.Parse(track);
-
- var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse;
-
- var uTrack = uBaseObject.Create(e);
-
- if (uTrack == null)
- return true;
-
- CurrentId = uTrack.Id;
-
- return true;
- }
-
- #endregion
-
- #region From XML
-
- private async Task GetAVProtocolAsync()
- {
- var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId);
- if (avService == null)
- return;
-
- var url = avService.SCPDURL;
- if (!url.Contains("/"))
- url = "/dmr/" + url;
- if (!url.StartsWith("/"))
- url = "/" + url;
-
- var httpClient = new SsdpHttpClient(_httpClient);
- var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
-
- AvCommands = TransportCommands.Create(document);
- }
-
- private async Task GetRenderingProtocolAsync()
- {
- var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId);
-
- if (avService == null)
- return;
- string url = avService.SCPDURL;
- if (!url.Contains("/"))
- url = "/dmr/" + url;
- if (!url.StartsWith("/"))
- url = "/" + url;
-
- var httpClient = new SsdpHttpClient(_httpClient);
- var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
-
- RendererCommands = TransportCommands.Create(document);
- }
-
- internal TransportCommands AvCommands
- {
- get;
- set;
- }
-
- internal TransportCommands RendererCommands
- {
- get;
- set;
- }
-
- public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, ILogger logger)
- {
- var ssdpHttpClient = new SsdpHttpClient(httpClient);
-
- var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false);
-
- var deviceProperties = new DeviceProperties();
-
- var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
- if (name != null)
- deviceProperties.Name = name.Value;
-
- var name2 = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
- if (name2 != null)
- deviceProperties.Name = name2.Value;
-
- var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
- if (model != null)
- deviceProperties.ModelName = model.Value;
-
- var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
- if (modelNumber != null)
- deviceProperties.ModelNumber = modelNumber.Value;
-
- var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
- if (uuid != null)
- deviceProperties.UUID = uuid.Value;
-
- var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
- if (manufacturer != null)
- deviceProperties.Manufacturer = manufacturer.Value;
-
- var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
- if (manufacturerUrl != null)
- deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
-
- var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
- if (presentationUrl != null)
- deviceProperties.PresentationUrl = presentationUrl.Value;
-
-
- deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
-
- var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
-
- if (icon != null)
- {
- deviceProperties.Icon = uIcon.Create(icon);
- }
-
- var isRenderer = false;
-
- foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
- {
- if (services == null)
- return null;
-
- var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
-
- if (servicesList == null)
- return null;
-
- foreach (var element in servicesList)
- {
- var service = uService.Create(element);
-
- if (service != null)
- {
- deviceProperties.Services.Add(service);
- if (service.ServiceId == ServiceAvtransportId)
- {
- isRenderer = true;
- }
- }
- }
- }
-
- if (isRenderer)
- {
-
- var device = new Device(deviceProperties, httpClient, logger);
-
- await device.GetRenderingProtocolAsync().ConfigureAwait(false);
- await device.GetAVProtocolAsync().ConfigureAwait(false);
-
- return device;
- }
-
- return null;
- }
-
- #endregion
-
- #region Events
-
- public event EventHandler<TransportStateEventArgs> PlaybackChanged;
- public event EventHandler<CurrentIdEventArgs> CurrentIdChanged;
-
- private void NotifyPlaybackChanged(bool value)
- {
- if (PlaybackChanged != null)
- {
- PlaybackChanged.Invoke(this, new TransportStateEventArgs
- {
- Stopped = IsStopped
- });
- }
- }
-
- private void NotifyCurrentIdChanged(string value)
- {
- if (CurrentIdChanged != null)
- CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value));
- }
-
- #endregion
-
- #region IDisposable
-
- bool _disposed;
- public void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
- _timer.Dispose();
- }
- }
-
- #endregion
-
- public override string ToString()
- {
- return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
- }
-
- private class TRANSPORTSTATE
- {
- public const string STOPPED = "STOPPED";
- public const string PLAYING = "PLAYING";
- public const string TRANSITIONING = "TRANSITIONING";
- public const string PAUSED_PLAYBACK = "PAUSED_PLAYBACK";
- public const string PAUSED = "PAUSED";
- }
-
- }
-}
+using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace MediaBrowser.Dlna.PlayTo +{ + public sealed class Device : IDisposable + { + const string ServiceAvtransportId = "urn:upnp-org:serviceId:AVTransport"; + const string ServiceRenderingId = "urn:upnp-org:serviceId:RenderingControl"; + + #region Fields & Properties + + private Timer _timer; + + public DeviceProperties Properties { get; set; } + + private int _muteVol; + public bool IsMuted + { + get + { + return _muteVol > 0; + } + } + + private string _currentId = String.Empty; + public string CurrentId + { + get + { + return _currentId; + } + set + { + if (_currentId == value) + return; + _currentId = value; + NotifyCurrentIdChanged(value); + } + } + + public int Volume { get; set; } + + public TimeSpan Duration { get; set; } + + private TimeSpan _position = TimeSpan.FromSeconds(0); + public TimeSpan Position + { + get + { + return _position; + } + set + { + _position = value; + } + } + + private string _transportState = String.Empty; + public string TransportState + { + get + { + return _transportState; + } + set + { + if (_transportState == value) + return; + + _transportState = value; + + if (value == "PLAYING" || value == "STOPPED") + NotifyPlaybackChanged(value == "STOPPED"); + } + } + + public bool IsPlaying + { + get + { + return TransportState == "PLAYING"; + } + } + + public bool IsTransitioning + { + get + { + return (TransportState == "TRANSITIONING"); + } + } + + public bool IsPaused + { + get + { + return TransportState == "PAUSED" || TransportState == "PAUSED_PLAYBACK"; + } + } + + public bool IsStopped + { + get + { + return (TransportState == "STOPPED"); + } + } + + public DateTime UpdateTime { get; private set; } + + #endregion + + private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + + public Device(DeviceProperties deviceProperties, IHttpClient httpClient, ILogger logger) + { + Properties = deviceProperties; + _httpClient = httpClient; + _logger = logger; + } + + private int GetTimerIntervalMs() + { + return 10000; + } + + public void Start() + { + UpdateTime = DateTime.UtcNow; + + var interval = GetTimerIntervalMs(); + + _timer = new Timer(TimerCallback, null, interval, interval); + } + + private void RestartTimer() + { + var interval = GetTimerIntervalMs(); + + _timer.Change(interval, interval); + } + + private void StopTimer() + { + _timer.Change(Timeout.Infinite, Timeout.Infinite); + } + + #region Commanding + + public Task<bool> VolumeDown(bool mute = false) + { + var sendVolume = (Volume - 5) > 0 ? Volume - 5 : 0; + if (mute && _muteVol == 0) + { + sendVolume = 0; + _muteVol = Volume; + } + return SetVolume(sendVolume); + } + + public Task<bool> VolumeUp(bool unmute = false) + { + var sendVolume = (Volume + 5) < 100 ? Volume + 5 : 100; + if (unmute && _muteVol > 0) + sendVolume = _muteVol; + _muteVol = 0; + return SetVolume(sendVolume); + } + + public Task ToggleMute() + { + if (_muteVol == 0) + { + _muteVol = Volume; + return SetVolume(0); + } + + var tmp = _muteVol; + _muteVol = 0; + return SetVolume(tmp); + } + + public async Task<bool> SetVolume(int value) + { + var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume"); + if (command == null) + return true; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, value)) + .ConfigureAwait(false); + Volume = value; + return true; + } + + public async Task<TimeSpan> Seek(TimeSpan value) + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek"); + if (command == null) + return value; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, String.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME")) + .ConfigureAwait(false); + + return value; + } + + public async Task<bool> SetAvTransport(string url, string header, string metaData) + { + StopTimer(); + + TransportState = "STOPPED"; + CurrentId = "0"; + + await Task.Delay(50).ConfigureAwait(false); + + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI"); + if (command == null) + return false; + + var dictionary = new Dictionary<string, string> + { + {"CurrentURI", url}, + {"CurrentURIMetaData", CreateDidlMeta(metaData)} + }; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, url, dictionary), header) + .ConfigureAwait(false); + + if (!IsPlaying) + { + await Task.Delay(50).ConfigureAwait(false); + await SetPlay().ConfigureAwait(false); + } + + _count = 5; + RestartTimer(); + + return true; + } + + private string CreateDidlMeta(string value) + { + if (value == null) + return String.Empty; + + var escapedData = value.Replace("<", "<").Replace(">", ">"); + + return String.Format(BaseDidl, escapedData.Replace("\r\n", "")); + } + + private const string BaseDidl = "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">{0}</DIDL-Lite>"; + + public async Task<bool> SetNextAvTransport(string value, string header, string metaData) + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetNextAVTransportURI"); + if (command == null) + return false; + + var dictionary = new Dictionary<string, string> + { + {"NextURI", value}, + {"NextURIMetaData", CreateDidlMeta(metaData)} + }; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, value, dictionary), header) + .ConfigureAwait(false); + + await Task.Delay(100).ConfigureAwait(false); + + return true; + } + + public async Task<bool> SetPlay() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play"); + if (command == null) + return false; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) + .ConfigureAwait(false); + + _count = 5; + return true; + } + + public async Task<bool> SetStop() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop"); + if (command == null) + return false; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) + .ConfigureAwait(false); + + await Task.Delay(50).ConfigureAwait(false); + _count = 4; + return true; + } + + public async Task<bool> SetPause() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause"); + if (command == null) + return false; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 0)) + .ConfigureAwait(false); + + await Task.Delay(50).ConfigureAwait(false); + TransportState = "PAUSED_PLAYBACK"; + return true; + } + + #endregion + + #region Get data + + // TODO: What is going on here + int _count = 5; + + private async void TimerCallback(object sender) + { + if (_disposed) + return; + + StopTimer(); + + try + { + var hasTrack = await GetPositionInfo().ConfigureAwait(false); + + // TODO: Why make these requests if hasTrack==false? + if (_count > 5) + { + await GetTransportInfo().ConfigureAwait(false); + if (!hasTrack) + { + await GetMediaInfo().ConfigureAwait(false); + } + await GetVolume().ConfigureAwait(false); + _count = 0; + } + } + catch (Exception ex) + { + _logger.ErrorException("Error updating device info", ex); + } + + _count++; + if (_disposed) + return; + + RestartTimer(); + } + + private async Task GetVolume() + { + var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume"); + if (command == null) + return; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) + .ConfigureAwait(false); + + if (result == null || result.Document == null) + return; + + var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null); + var volumeValue = volume == null ? null : volume.Value; + + if (volumeValue == null) + return; + + Volume = Int32.Parse(volumeValue); + + //Reset the Mute value if Volume is bigger than zero + if (Volume > 0 && _muteVol > 0) + { + _muteVol = 0; + } + } + + private async Task GetTransportInfo() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo"); + if (command == null) + return; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + if (service == null) + return; + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) + .ConfigureAwait(false); + + if (result == null || result.Document == null) + return; + + var transportState = + result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null); + + var transportStateValue = transportState == null ? null : transportState.Value; + + if (transportStateValue != null) + TransportState = transportStateValue; + + UpdateTime = DateTime.UtcNow; + } + + private async Task GetMediaInfo() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo"); + if (command == null) + return; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) + .ConfigureAwait(false); + + if (result == null || result.Document == null) + return; + + var track = result.Document.Descendants("CurrentURIMetaData").Select(i => i.Value).FirstOrDefault(); + + if (String.IsNullOrEmpty(track)) + { + CurrentId = "0"; + return; + } + + var uPnpResponse = XElement.Parse(track); + + var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse; + + var uTrack = uParser.CreateObjectFromXML(new uParserObject + { + Type = e.GetValue(uPnpNamespaces.uClass), + Element = e + }); + + if (uTrack != null) + CurrentId = uTrack.Id; + } + + private async Task<bool> GetPositionInfo() + { + var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo"); + if (command == null) + return true; + + var service = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType)) + .ConfigureAwait(false); + + if (result == null || result.Document == null) + return true; + + var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null); + var duration = durationElem == null ? null : durationElem.Value; + + if (duration != null) + { + Duration = TimeSpan.Parse(duration); + } + + var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null); + var position = positionElem == null ? null : positionElem.Value; + + if (position != null) + { + Position = TimeSpan.Parse(position); + } + + var track = result.Document.Descendants("TrackMetaData").Select(i => i.Value) + .FirstOrDefault(); + + if (String.IsNullOrEmpty(track)) + { + //If track is null, some vendors do this, use GetMediaInfo instead + return false; + } + + var uPnpResponse = XElement.Parse(track); + + var e = uPnpResponse.Element(uPnpNamespaces.items) ?? uPnpResponse; + + var uTrack = uBaseObject.Create(e); + + if (uTrack == null) + return true; + + CurrentId = uTrack.Id; + + return true; + } + + #endregion + + #region From XML + + private async Task GetAVProtocolAsync() + { + var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceAvtransportId); + if (avService == null) + return; + + var url = avService.SCPDURL; + if (!url.Contains("/")) + url = "/dmr/" + url; + if (!url.StartsWith("/")) + url = "/" + url; + + var httpClient = new SsdpHttpClient(_httpClient); + var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); + + AvCommands = TransportCommands.Create(document); + } + + private async Task GetRenderingProtocolAsync() + { + var avService = Properties.Services.FirstOrDefault(s => s.ServiceId == ServiceRenderingId); + + if (avService == null) + return; + string url = avService.SCPDURL; + if (!url.Contains("/")) + url = "/dmr/" + url; + if (!url.StartsWith("/")) + url = "/" + url; + + var httpClient = new SsdpHttpClient(_httpClient); + var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); + + RendererCommands = TransportCommands.Create(document); + } + + internal TransportCommands AvCommands + { + get; + set; + } + + internal TransportCommands RendererCommands + { + get; + set; + } + + public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, ILogger logger) + { + var ssdpHttpClient = new SsdpHttpClient(httpClient); + + var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false); + + var deviceProperties = new DeviceProperties(); + + var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault(); + if (name != null) + deviceProperties.Name = name.Value; + + var name2 = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault(); + if (name2 != null) + deviceProperties.Name = name2.Value; + + var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault(); + if (model != null) + deviceProperties.ModelName = model.Value; + + var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault(); + if (modelNumber != null) + deviceProperties.ModelNumber = modelNumber.Value; + + var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault(); + if (uuid != null) + deviceProperties.UUID = uuid.Value; + + var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault(); + if (manufacturer != null) + deviceProperties.Manufacturer = manufacturer.Value; + + var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault(); + if (manufacturerUrl != null) + deviceProperties.ManufacturerUrl = manufacturerUrl.Value; + + var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault(); + if (presentationUrl != null) + deviceProperties.PresentationUrl = presentationUrl.Value; + + + deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port); + + var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault(); + + if (icon != null) + { + deviceProperties.Icon = uIcon.Create(icon); + } + + var isRenderer = false; + + foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList"))) + { + if (services == null) + return null; + + var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service")); + + if (servicesList == null) + return null; + + foreach (var element in servicesList) + { + var service = uService.Create(element); + + if (service != null) + { + deviceProperties.Services.Add(service); + if (service.ServiceId == ServiceAvtransportId) + { + isRenderer = true; + } + } + } + } + + if (isRenderer) + { + + var device = new Device(deviceProperties, httpClient, logger); + + await device.GetRenderingProtocolAsync().ConfigureAwait(false); + await device.GetAVProtocolAsync().ConfigureAwait(false); + + return device; + } + + return null; + } + + #endregion + + #region Events + + public event EventHandler<TransportStateEventArgs> PlaybackChanged; + public event EventHandler<CurrentIdEventArgs> CurrentIdChanged; + + private void NotifyPlaybackChanged(bool value) + { + if (PlaybackChanged != null) + { + PlaybackChanged.Invoke(this, new TransportStateEventArgs + { + Stopped = IsStopped + }); + } + } + + private void NotifyCurrentIdChanged(string value) + { + if (CurrentIdChanged != null) + CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value)); + } + + #endregion + + #region IDisposable + + bool _disposed; + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + _timer.Dispose(); + } + } + + #endregion + + public override string ToString() + { + return String.Format("{0} - {1}", Properties.Name, Properties.BaseUrl); + } + } +} diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index 8bf9ec9f6..48ef5e589 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);
- }
- }
- }
-
- /// <summary>
- /// Handles the Elapsed event of the updateTimer control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ElapsedEventArgs"/> instance containing the event data.</param>
- async void updateTimer_Elapsed(object sender, ElapsedEventArgs e)
- {
- if (_disposed)
- return;
-
- ((Timer)sender).Stop();
-
-
- if(!IsSessionActive)
- {
- //Session is inactive, mark it for Disposal and don't start the elapsed timer.
- await _sessionManager.ReportSessionEnded(this._session.Id);
- return;
- }
-
- await ReportProgress().ConfigureAwait(false);
-
- if (!_disposed && IsSessionActive)
- ((Timer)sender).Start();
- }
-
- /// <summary>
- /// Reports the playback progress.
- /// </summary>
- /// <returns></returns>
- private async Task ReportProgress()
- {
- if (_currentItem == null || _device.IsStopped)
- return;
-
- if (!_playbackStarted)
- {
- await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false);
- _playbackStarted = true;
- }
-
- if ((_device.IsPlaying || _device.IsPaused))
- {
- var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1);
- if (playlistItem != null && playlistItem.Transcode)
- {
- await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo
- {
- Item = _currentItem,
- SessionId = _session.Id,
- PositionTicks = _device.Position.Ticks + playlistItem.StartPositionTicks,
- IsMuted = _device.IsMuted,
- IsPaused = _device.IsPaused
-
- }).ConfigureAwait(false);
- }
- else if (_currentItem != null)
- {
- await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo
- {
- Item = _currentItem,
- SessionId = _session.Id,
- PositionTicks = _device.Position.Ticks,
- IsMuted = _device.IsMuted,
- IsPaused = _device.IsPaused
-
- }).ConfigureAwait(false);
- }
- }
- }
-
- #endregion
-
- #region SendCommands
-
- public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
- {
- _logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand);
-
- var items = new List<BaseItem>();
- foreach (string id in command.ItemIds)
- {
- AddItemFromId(Guid.Parse(id), items);
- }
-
- var playlist = new List<PlaylistItem>();
- var isFirst = true;
-
- var serverAddress = GetServerAddress();
-
- foreach (var item in items)
- {
- if (isFirst && command.StartPositionTicks.HasValue)
- {
- playlist.Add(CreatePlaylistItem(item, command.StartPositionTicks.Value, serverAddress));
- isFirst = false;
- }
- else
- {
- playlist.Add(CreatePlaylistItem(item, 0, serverAddress));
- }
- }
-
- _logger.Debug("{0} - Playlist created", _session.DeviceName);
-
- if (command.PlayCommand == PlayCommand.PlayLast)
- {
- AddItemsToPlaylist(playlist);
- return Task.FromResult(true);
- }
- if (command.PlayCommand == PlayCommand.PlayNext)
- {
- AddItemsToPlaylist(playlist);
- return Task.FromResult(true);
- }
-
- _logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count);
- return PlayItems(playlist);
- }
-
- public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
- {
- switch (command.Command)
- {
- case PlaystateCommand.Stop:
- Playlist.Clear();
- return _device.SetStop();
-
- case PlaystateCommand.Pause:
- return _device.SetPause();
-
- case PlaystateCommand.Unpause:
- return _device.SetPlay();
-
- case PlaystateCommand.Seek:
- var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1);
- if (playlistItem != null && playlistItem.Transcode && playlistItem.IsVideo && _currentItem != null)
- {
- var newItem = CreatePlaylistItem(_currentItem, command.SeekPositionTicks ?? 0, GetServerAddress());
- playlistItem.StartPositionTicks = newItem.StartPositionTicks;
- playlistItem.StreamUrl = newItem.StreamUrl;
- playlistItem.Didl = newItem.Didl;
- return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl);
-
- }
- return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0));
-
-
- case PlaystateCommand.NextTrack:
- _currentItem = null;
- return SetNext();
-
- case PlaystateCommand.PreviousTrack:
- _currentItem = null;
- return SetPrevious();
- }
-
- return Task.FromResult(true);
- }
-
- public Task SendSystemCommand(SystemCommand command, CancellationToken cancellationToken)
- {
- switch (command)
- {
- case SystemCommand.VolumeDown:
- return _device.VolumeDown();
- case SystemCommand.VolumeUp:
- return _device.VolumeUp();
- case SystemCommand.Mute:
- return _device.VolumeDown(true);
- case SystemCommand.Unmute:
- return _device.VolumeUp(true);
- case SystemCommand.ToggleMute:
- return _device.ToggleMute();
- default:
- return Task.FromResult(true);
- }
- }
-
- public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendServerRestartNotification(CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendServerShutdownNotification(CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendBrowseCommand(BrowseRequest command, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- public Task SendMessageCommand(MessageCommand command, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
-
- #endregion
-
- #region Playlist
-
- private List<PlaylistItem> _playlist = new List<PlaylistItem>();
-
- private List<PlaylistItem> Playlist
- {
- get
- {
- return _playlist;
- }
- set
- {
- _playlist = value;
- }
- }
-
- private void AddItemFromId(Guid id, List<BaseItem> list)
- {
- var item = _libraryManager.GetItemById(id);
- if (item.IsFolder)
- {
- foreach (var childId in _itemRepository.GetChildren(item.Id))
- {
- AddItemFromId(childId, list);
- }
- }
- else
- {
- if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video)
- {
- list.Add(item);
- }
- }
- }
-
- private string GetServerAddress()
- {
- return string.Format("{0}://{1}:{2}/mediabrowser",
-
- "http",
- _networkManager.GetLocalIpAddresses().FirstOrDefault() ?? "localhost",
- "8096"
- );
- }
-
- private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
- {
- var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList();
-
- var playlistItem = PlaylistItem.GetBasicConfig(item, _transcodeSettings);
- playlistItem.StartPositionTicks = startPostionTicks;
-
- if (playlistItem.IsAudio)
- playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
- else
- {
- playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
- }
-
- var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
- playlistItem.Didl = didl;
-
- var header = StreamHelper.GetDlnaHeaders(playlistItem);
- playlistItem.DlnaHeaders = header;
- return playlistItem;
- }
-
- /// <summary>
- /// Plays the items.
- /// </summary>
- /// <param name="items">The items.</param>
- /// <returns></returns>
- private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items)
- {
- Playlist.Clear();
- Playlist.AddRange(items);
- await SetNext();
- return true;
- }
-
- /// <summary>
- /// Adds the items to playlist.
- /// </summary>
- /// <param name="items">The items.</param>
- private void AddItemsToPlaylist(IEnumerable<PlaylistItem> items)
- {
- Playlist.AddRange(items);
- }
-
- private async Task<bool> SetNext()
- {
- if (!Playlist.Any() || Playlist.All(i => i.PlayState != 0))
- {
- return true;
- }
- var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1);
-
- if (currentitem != null)
- {
- currentitem.PlayState = 2;
- }
-
- var nextTrack = Playlist.FirstOrDefault(i => i.PlayState == 0);
- if (nextTrack == null)
- {
- await _device.SetStop();
- return true;
- }
- nextTrack.PlayState = 1;
- await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl);
- if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
- await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
- return true;
- }
-
- public Task<bool> SetPrevious()
- {
- if (!Playlist.Any() || Playlist.All(i => i.PlayState != 2))
- return Task.FromResult(false);
-
- var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1);
-
- var prevTrack = Playlist.LastOrDefault(i => i.PlayState == 2);
-
- if (currentitem != null)
- {
- currentitem.PlayState = 0;
- }
-
- if (prevTrack == null)
- return Task.FromResult(false);
-
- prevTrack.PlayState = 1;
- return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl);
- }
-
- #endregion
-
- private bool _disposed;
-
- public void Dispose()
- {
- if (!_disposed)
- {
- _updateTimer.Stop();
- _disposed = true;
- _device.Dispose();
- _logger.Log(LogSeverity.Debug, "PlayTo - Controller disposed");
- }
- }
- }
-}
+using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Session; +using MediaBrowser.Dlna.PlayTo.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Session; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Timers; +using Timer = System.Timers.Timer; + +namespace MediaBrowser.Dlna.PlayTo +{ + public class PlayToController : ISessionController, IDisposable + { + private Device _device; + private BaseItem _currentItem = null; + private TranscodeSettings[] _transcodeSettings; + private readonly SessionInfo _session; + private readonly ISessionManager _sessionManager; + private readonly IItemRepository _itemRepository; + private readonly ILibraryManager _libraryManager; + private readonly INetworkManager _networkManager; + private readonly ILogger _logger; + private bool _playbackStarted = false; + + public bool SupportsMediaRemoteControl + { + get { return true; } + } + + public bool IsSessionActive + { + get + { + if (_device == null || _device.UpdateTime == default(DateTime)) + return false; + + return DateTime.UtcNow <= _device.UpdateTime.AddSeconds(30); + } + } + + public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager) + { + _session = session; + _itemRepository = itemRepository; + _sessionManager = sessionManager; + _libraryManager = libraryManager; + _networkManager = networkManager; + _logger = logger; + } + + public void Init(Device device, TranscodeSettings[] transcodeSettings) + { + _transcodeSettings = transcodeSettings; + _device = device; + _device.PlaybackChanged += Device_PlaybackChanged; + _device.CurrentIdChanged += Device_CurrentIdChanged; + _device.Start(); + + _updateTimer = new Timer(1000); + _updateTimer.Elapsed += updateTimer_Elapsed; + _updateTimer.Start(); + } + + #region Device EventHandlers & Update Timer + + Timer _updateTimer; + + async void Device_PlaybackChanged(object sender, TransportStateEventArgs e) + { + if (_currentItem == null) + return; + + if (e.Stopped == false) + await ReportProgress().ConfigureAwait(false); + + else if (e.Stopped && _playbackStarted) + { + _playbackStarted = false; + + await _sessionManager.OnPlaybackStopped(new PlaybackStopInfo + { + Item = _currentItem, + SessionId = _session.Id, + PositionTicks = _device.Position.Ticks + + }).ConfigureAwait(false); + + await SetNext().ConfigureAwait(false); + } + } + + async void Device_CurrentIdChanged(object sender, CurrentIdEventArgs e) + { + if (e.Id != Guid.Empty) + { + if (_currentItem != null && _currentItem.Id == e.Id) + { + return; + } + + var item = _libraryManager.GetItemById(e.Id); + + if (item != null) + { + _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id); + _currentItem = item; + _playbackStarted = false; + + await ReportProgress().ConfigureAwait(false); + } + } + } + + /// <summary> + /// Handles the Elapsed event of the updateTimer control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="ElapsedEventArgs"/> instance containing the event data.</param> + async void updateTimer_Elapsed(object sender, ElapsedEventArgs e) + { + if (_disposed) + return; + + ((Timer)sender).Stop(); + + await ReportProgress().ConfigureAwait(false); + + if (!_disposed && IsSessionActive) + ((Timer)sender).Start(); + } + + /// <summary> + /// Reports the playback progress. + /// </summary> + /// <returns></returns> + private async Task ReportProgress() + { + if (_currentItem == null || _device.IsStopped) + return; + + if (!_playbackStarted) + { + await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false); + _playbackStarted = true; + } + + if ((_device.IsPlaying || _device.IsPaused)) + { + var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1); + if (playlistItem != null && playlistItem.Transcode) + { + await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo + { + Item = _currentItem, + SessionId = _session.Id, + PositionTicks = _device.Position.Ticks + playlistItem.StartPositionTicks, + IsMuted = _device.IsMuted, + IsPaused = _device.IsPaused + + }).ConfigureAwait(false); + } + else if (_currentItem != null) + { + await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo + { + Item = _currentItem, + SessionId = _session.Id, + PositionTicks = _device.Position.Ticks, + IsMuted = _device.IsMuted, + IsPaused = _device.IsPaused + + }).ConfigureAwait(false); + } + } + } + + #endregion + + #region SendCommands + + public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken) + { + _logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand); + + var items = new List<BaseItem>(); + foreach (string id in command.ItemIds) + { + AddItemFromId(Guid.Parse(id), items); + } + + var playlist = new List<PlaylistItem>(); + var isFirst = true; + + var serverAddress = GetServerAddress(); + + foreach (var item in items) + { + if (isFirst && command.StartPositionTicks.HasValue) + { + playlist.Add(CreatePlaylistItem(item, command.StartPositionTicks.Value, serverAddress)); + isFirst = false; + } + else + { + playlist.Add(CreatePlaylistItem(item, 0, serverAddress)); + } + } + + _logger.Debug("{0} - Playlist created", _session.DeviceName); + + if (command.PlayCommand == PlayCommand.PlayLast) + { + AddItemsToPlaylist(playlist); + return Task.FromResult(true); + } + if (command.PlayCommand == PlayCommand.PlayNext) + { + AddItemsToPlaylist(playlist); + return Task.FromResult(true); + } + + _logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count); + return PlayItems(playlist); + } + + public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken) + { + switch (command.Command) + { + case PlaystateCommand.Stop: + Playlist.Clear(); + return _device.SetStop(); + + case PlaystateCommand.Pause: + return _device.SetPause(); + + case PlaystateCommand.Unpause: + return _device.SetPlay(); + + case PlaystateCommand.Seek: + var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1); + if (playlistItem != null && playlistItem.Transcode && playlistItem.IsVideo && _currentItem != null) + { + var newItem = CreatePlaylistItem(_currentItem, command.SeekPositionTicks ?? 0, GetServerAddress()); + playlistItem.StartPositionTicks = newItem.StartPositionTicks; + playlistItem.StreamUrl = newItem.StreamUrl; + playlistItem.Didl = newItem.Didl; + return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl); + + } + return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0)); + + + case PlaystateCommand.NextTrack: + _currentItem = null; + return SetNext(); + + case PlaystateCommand.PreviousTrack: + _currentItem = null; + return SetPrevious(); + } + + return Task.FromResult(true); + } + + public Task SendSystemCommand(SystemCommand command, CancellationToken cancellationToken) + { + switch (command) + { + case SystemCommand.VolumeDown: + return _device.VolumeDown(); + case SystemCommand.VolumeUp: + return _device.VolumeUp(); + case SystemCommand.Mute: + return _device.VolumeDown(true); + case SystemCommand.Unmute: + return _device.VolumeUp(true); + case SystemCommand.ToggleMute: + return _device.ToggleMute(); + default: + return Task.FromResult(true); + } + } + + public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendRestartRequiredNotification(CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendServerRestartNotification(CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendServerShutdownNotification(CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendBrowseCommand(BrowseRequest command, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public Task SendMessageCommand(MessageCommand command, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + #endregion + + #region Playlist + + private List<PlaylistItem> _playlist = new List<PlaylistItem>(); + + private List<PlaylistItem> Playlist + { + get + { + return _playlist; + } + set + { + _playlist = value; + } + } + + private void AddItemFromId(Guid id, List<BaseItem> list) + { + var item = _libraryManager.GetItemById(id); + if (item.IsFolder) + { + foreach (var childId in _itemRepository.GetChildren(item.Id)) + { + AddItemFromId(childId, list); + } + } + else + { + if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video) + { + list.Add(item); + } + } + } + + private string GetServerAddress() + { + return string.Format("{0}://{1}:{2}/mediabrowser", + + "http", + _networkManager.GetLocalIpAddresses().FirstOrDefault() ?? "localhost", + "8096" + ); + } + + private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress) + { + var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList(); + + var playlistItem = PlaylistItem.GetBasicConfig(item, _transcodeSettings); + playlistItem.StartPositionTicks = startPostionTicks; + + if (playlistItem.IsAudio) + playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress); + else + { + playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress); + } + + var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams); + playlistItem.Didl = didl; + + var header = StreamHelper.GetDlnaHeaders(playlistItem); + playlistItem.DlnaHeaders = header; + return playlistItem; + } + + /// <summary> + /// Plays the items. + /// </summary> + /// <param name="items">The items.</param> + /// <returns></returns> + private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items) + { + Playlist.Clear(); + Playlist.AddRange(items); + await SetNext(); + return true; + } + + /// <summary> + /// Adds the items to playlist. + /// </summary> + /// <param name="items">The items.</param> + private void AddItemsToPlaylist(IEnumerable<PlaylistItem> items) + { + Playlist.AddRange(items); + } + + private async Task<bool> SetNext() + { + if (!Playlist.Any() || Playlist.All(i => i.PlayState != 0)) + { + return true; + } + var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1); + + if (currentitem != null) + { + currentitem.PlayState = 2; + } + + var nextTrack = Playlist.FirstOrDefault(i => i.PlayState == 0); + if (nextTrack == null) + { + await _device.SetStop(); + return true; + } + nextTrack.PlayState = 1; + await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl); + if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode) + await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks)); + return true; + } + + public Task<bool> SetPrevious() + { + if (!Playlist.Any() || Playlist.All(i => i.PlayState != 2)) + return Task.FromResult(false); + + var currentitem = Playlist.FirstOrDefault(i => i.PlayState == 1); + + var prevTrack = Playlist.LastOrDefault(i => i.PlayState == 2); + + if (currentitem != null) + { + currentitem.PlayState = 0; + } + + if (prevTrack == null) + return Task.FromResult(false); + + prevTrack.PlayState = 1; + return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl); + } + + #endregion + + private bool _disposed; + + public void Dispose() + { + if (!_disposed) + { + _updateTimer.Stop(); + _disposed = true; + _device.Dispose(); + _logger.Log(LogSeverity.Debug, "PlayTo - Controller disposed"); + } + } + } +} diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 594179fd9..7ac158065 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 |
