@ -19,15 +19,40 @@ namespace Emby.Dlna.PlayTo
{
public class Device : IDisposable
{
private static readonly CultureInfo UsCulture = new CultureInfo ( "en-US" ) ;
private readonly IHttpClient _httpClient ;
private readonly ILogger _logger ;
private readonly object _timerLock = new object ( ) ;
private Timer _timer ;
private int _muteVol ;
private int _volume ;
private DateTime _lastVolumeRefresh ;
private bool _volumeRefreshActive ;
private int _connectFailureCount ;
private bool _disposed ;
public Device ( DeviceInfo deviceProperties , IHttpClient httpClient , ILogger logger )
{
Properties = deviceProperties ;
_httpClient = httpClient ;
_logger = logger ;
}
public event EventHandler < PlaybackStartEventArgs > PlaybackStart ;
public event EventHandler < PlaybackProgressEventArgs > PlaybackProgress ;
public event EventHandler < PlaybackStoppedEventArgs > PlaybackStopped ;
public event EventHandler < MediaChangedEventArgs > MediaChanged ;
public DeviceInfo Properties { get ; set ; }
private int _muteVol ;
public bool IsMuted { get ; set ; }
private int _volume ;
public int Volume
{
get
@ -43,29 +68,21 @@ namespace Emby.Dlna.PlayTo
public TimeSpan Position { get ; set ; } = TimeSpan . FromSeconds ( 0 ) ;
public TRANSPORTSTATE TransportState { get ; private set ; }
public bool IsPlaying = > TransportState = = TRANSPORTSTATE . PLAYING ;
public TransportState TransportState { get ; private set ; }
public bool IsP aused = > TransportState = = TRANSPORTSTATE . PAUSED | | TransportState = = TRANSPORTSTATE . PAUSED_PLAYBACK ;
public bool IsPlaying = > TransportState = = TransportState . Playing ;
public bool Is Stopped = > TransportState = = TRANSPORTSTATE . STOPPED ;
public bool Is Paused = > TransportState = = TransportState . Paused | | TransportState = = TransportState . PausedPlayback ;
p rivate readonly IHttpClient _httpClient ;
p ublic bool IsStopped = > TransportState = = TransportState . Stopped ;
p rivate readonly ILogger _logger ;
p ublic Action OnDeviceUnavailable { get ; set ; }
private readonly IServerConfigurationManager _config ;
private TransportCommands AvCommands { get ; set ; }
p ublic Action OnDeviceUnavailable { get ; set ; }
p rivate TransportCommands RendererCommands { get ; set ; }
public Device ( DeviceInfo deviceProperties , IHttpClient httpClient , ILogger logger , IServerConfigurationManager config )
{
Properties = deviceProperties ;
_httpClient = httpClient ;
_logger = logger ;
_config = config ;
}
public UBaseObject CurrentMediaInfo { get ; private set ; }
public void Start ( )
{
@ -73,8 +90,6 @@ namespace Emby.Dlna.PlayTo
_timer = new Timer ( TimerCallback , null , 1000 , Timeout . Infinite ) ;
}
private DateTime _lastVolumeRefresh ;
private bool _volumeRefreshActive ;
private Task RefreshVolumeIfNeeded ( )
{
if ( _volumeRefreshActive
@ -105,7 +120,6 @@ namespace Emby.Dlna.PlayTo
}
}
private readonly object _timerLock = new object ( ) ;
private void RestartTimer ( bool immediate = false )
{
lock ( _timerLock )
@ -233,6 +247,9 @@ namespace Emby.Dlna.PlayTo
/// <summary>
/// Sets volume on a scale of 0-100.
/// </summary>
/// <param name="value">The volume on a scale of 0-100.</param>
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task SetVolume ( int value , CancellationToken cancellationToken )
{
var rendererCommands = await GetRenderingProtocolAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
@ -275,7 +292,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException ( "Unable to find service" ) ;
}
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" ) )
await new SsdpHttpClient ( _httpClient ) . SendCommandAsync ( Properties . BaseUrl , service , command . Name , avCommands . BuildPost ( command , service . ServiceType , string . Format ( CultureInfo . InvariantCulture , "{0:hh}:{0:mm}:{0:ss}" , value ) , "REL_TIME" ) )
. ConfigureAwait ( false ) ;
RestartTimer ( true ) ;
@ -285,7 +302,7 @@ namespace Emby.Dlna.PlayTo
{
var avCommands = await GetAVProtocolAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
url = url . Replace ( "&" , "&" );
url = url . Replace ( "&" , "&" , StringComparison . Ordinal );
_logger . LogDebug ( "{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}" , Properties . Name , url , header ) ;
@ -297,8 +314,8 @@ namespace Emby.Dlna.PlayTo
var dictionary = new Dictionary < string , string >
{
{ "CurrentURI" , url } ,
{ "CurrentURIMetaData" , CreateDidlMeta ( metaData ) }
{ "CurrentURI" , url } ,
{ "CurrentURIMetaData" , CreateDidlMeta ( metaData ) }
} ;
var service = GetAvTransportService ( ) ;
@ -401,13 +418,11 @@ namespace Emby.Dlna.PlayTo
await new SsdpHttpClient ( _httpClient ) . SendCommandAsync ( Properties . BaseUrl , service , command . Name , avCommands . BuildPost ( command , service . ServiceType , 1 ) )
. ConfigureAwait ( false ) ;
TransportState = T RANSPORTSTATE. PAUSED ;
TransportState = T ransportState. Paused ;
RestartTimer ( true ) ;
}
private int _connectFailureCount ;
private async void TimerCallback ( object sender )
{
if ( _disposed )
@ -436,7 +451,7 @@ namespace Emby.Dlna.PlayTo
if ( transportState . HasValue )
{
// If we're not playing anything no need to get additional data
if ( transportState . Value = = T RANSPORTSTATE. STOPPED )
if ( transportState . Value = = T ransportState. Stopped )
{
UpdateMediaInfo ( null , transportState . Value ) ;
}
@ -465,7 +480,7 @@ namespace Emby.Dlna.PlayTo
}
// If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive
if ( transportState . Value = = T RANSPORTSTATE. STOPPED )
if ( transportState . Value = = T ransportState. Stopped )
{
RestartTimerInactive ( ) ;
}
@ -539,7 +554,7 @@ namespace Emby.Dlna.PlayTo
return ;
}
var volume = result . Document . Descendants ( u PnpNamespaces. RenderingControl + "GetVolumeResponse" ) . Select ( i = > i . Element ( "CurrentVolume" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var volume = result . Document . Descendants ( U PnpNamespaces. RenderingControl + "GetVolumeResponse" ) . Select ( i = > i . Element ( "CurrentVolume" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var volumeValue = volume ? . Value ;
if ( string . IsNullOrWhiteSpace ( volumeValue ) )
@ -589,14 +604,14 @@ namespace Emby.Dlna.PlayTo
return ;
}
var valueNode = result . Document . Descendants ( u PnpNamespaces. RenderingControl + "GetMuteResponse" )
var valueNode = result . Document . Descendants ( U PnpNamespaces. RenderingControl + "GetMuteResponse" )
. Select ( i = > i . Element ( "CurrentMute" ) )
. FirstOrDefault ( i = > i ! = null ) ;
IsMuted = string . Equals ( valueNode ? . Value , "1" , StringComparison . OrdinalIgnoreCase ) ;
}
private async Task < T RANSPORTSTATE ? > GetTransportInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
private async Task < T ransportState ? > GetTransportInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
{
var command = avCommands . ServiceActions . FirstOrDefault ( c = > c . Name = = "GetTransportInfo" ) ;
if ( command = = null )
@ -623,12 +638,12 @@ namespace Emby.Dlna.PlayTo
}
var transportState =
result . Document . Descendants ( u PnpNamespaces. AvTransport + "GetTransportInfoResponse" ) . Select ( i = > i . Element ( "CurrentTransportState" ) ) . FirstOrDefault ( i = > i ! = null ) ;
result . Document . Descendants ( U PnpNamespaces. AvTransport + "GetTransportInfoResponse" ) . Select ( i = > i . Element ( "CurrentTransportState" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var transportStateValue = transportState ? . Value ;
if ( transportStateValue ! = null
& & Enum . TryParse ( transportStateValue , true , out T RANSPORTSTATE state ) )
& & Enum . TryParse ( transportStateValue , true , out T ransportState state ) )
{
return state ;
}
@ -636,7 +651,7 @@ namespace Emby.Dlna.PlayTo
return null ;
}
private async Task < u BaseObject> GetMediaInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
private async Task < U BaseObject> GetMediaInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
{
var command = avCommands . ServiceActions . FirstOrDefault ( c = > c . Name = = "GetMediaInfo" ) ;
if ( command = = null )
@ -671,7 +686,7 @@ namespace Emby.Dlna.PlayTo
return null ;
}
var e = track . Element ( uPnpNamespaces. i tems) ? ? track ;
var e = track . Element ( UPnpNamespaces. I tems) ? ? track ;
var elementString = ( string ) e ;
@ -687,13 +702,13 @@ namespace Emby.Dlna.PlayTo
return null ;
}
e = track . Element ( uPnpNamespaces. i tems) ? ? track ;
e = track . Element ( UPnpNamespaces. I tems) ? ? track ;
elementString = ( string ) e ;
if ( ! string . IsNullOrWhiteSpace ( elementString ) )
{
return new u BaseObject
return new U BaseObject
{
Url = elementString
} ;
@ -702,7 +717,7 @@ namespace Emby.Dlna.PlayTo
return null ;
}
private async Task < ( bool , u BaseObject) > GetPositionInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
private async Task < ( bool , U BaseObject) > GetPositionInfo ( TransportCommands avCommands , CancellationToken cancellationToken )
{
var command = avCommands . ServiceActions . FirstOrDefault ( c = > c . Name = = "GetPositionInfo" ) ;
if ( command = = null )
@ -731,11 +746,11 @@ namespace Emby.Dlna.PlayTo
return ( false , null ) ;
}
var trackUriElem = result . Document . Descendants ( u PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "TrackURI" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var trackUri = trackUriElem = = null ? null : trackUriElem . Value ;
var trackUriElem = result . Document . Descendants ( U PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "TrackURI" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var trackUri = trackUriElem ? . Value ;
var durationElem = result . Document . Descendants ( u PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "TrackDuration" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var duration = durationElem = = null ? null : durationElem . Value ;
var durationElem = result . Document . Descendants ( U PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "TrackDuration" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var duration = durationElem ? . Value ;
if ( ! string . IsNullOrWhiteSpace ( duration )
& & ! string . Equals ( duration , "NOT_IMPLEMENTED" , StringComparison . OrdinalIgnoreCase ) )
@ -747,8 +762,8 @@ namespace Emby.Dlna.PlayTo
Duration = null ;
}
var positionElem = result . Document . Descendants ( u PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "RelTime" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var position = positionElem = = null ? null : positionElem . Value ;
var positionElem = result . Document . Descendants ( U PnpNamespaces. AvTransport + "GetPositionInfoResponse" ) . Select ( i = > i . Element ( "RelTime" ) ) . FirstOrDefault ( i = > i ! = null ) ;
var position = positionElem ? . Value ;
if ( ! string . IsNullOrWhiteSpace ( position ) & & ! string . Equals ( position , "NOT_IMPLEMENTED" , StringComparison . OrdinalIgnoreCase ) )
{
@ -787,7 +802,7 @@ namespace Emby.Dlna.PlayTo
return ( true , null ) ;
}
var e = uPnpResponse . Element ( uPnpNamespaces. i tems) ;
var e = uPnpResponse . Element ( UPnpNamespaces. I tems) ;
var uTrack = CreateUBaseObject ( e , trackUri ) ;
@ -819,7 +834,7 @@ namespace Emby.Dlna.PlayTo
// some devices send back invalid xml
try
{
return XElement . Parse ( xml . Replace ( "&" , "&" )) ;
return XElement . Parse ( xml . Replace ( "&" , "&" , StringComparison . Ordinal )) ;
}
catch ( XmlException )
{
@ -828,27 +843,27 @@ namespace Emby.Dlna.PlayTo
return null ;
}
private static u BaseObject CreateUBaseObject ( XElement container , string trackUri )
private static U BaseObject CreateUBaseObject ( XElement container , string trackUri )
{
if ( container = = null )
{
throw new ArgumentNullException ( nameof ( container ) ) ;
}
var url = container . GetValue ( u PnpNamespaces. Res ) ;
var url = container . GetValue ( U PnpNamespaces. Res ) ;
if ( string . IsNullOrWhiteSpace ( url ) )
{
url = trackUri ;
}
return new u BaseObject
return new U BaseObject
{
Id = container . GetAttributeValue ( u PnpNamespaces. Id ) ,
ParentId = container . GetAttributeValue ( u PnpNamespaces. ParentId ) ,
Title = container . GetValue ( uPnpNamespaces. t itle) ,
IconUrl = container . GetValue ( u PnpNamespaces. Artwork ) ,
SecondText = "" ,
Id = container . GetAttributeValue ( U PnpNamespaces. Id ) ,
ParentId = container . GetAttributeValue ( U PnpNamespaces. ParentId ) ,
Title = container . GetValue ( UPnpNamespaces. T itle) ,
IconUrl = container . GetValue ( U PnpNamespaces. Artwork ) ,
SecondText = string . Empty ,
Url = url ,
ProtocolInfo = GetProtocolInfo ( container ) ,
MetaData = container . ToString ( )
@ -862,11 +877,11 @@ namespace Emby.Dlna.PlayTo
throw new ArgumentNullException ( nameof ( container ) ) ;
}
var resElement = container . Element ( u PnpNamespaces. Res ) ;
var resElement = container . Element ( U PnpNamespaces. Res ) ;
if ( resElement ! = null )
{
var info = resElement . Attribute ( u PnpNamespaces. ProtocolInfo ) ;
var info = resElement . Attribute ( U PnpNamespaces. ProtocolInfo ) ;
if ( info ! = null & & ! string . IsNullOrWhiteSpace ( info . Value ) )
{
@ -941,12 +956,12 @@ namespace Emby.Dlna.PlayTo
return url ;
}
if ( ! url . Contains ( "/" ) )
if ( ! url . Contains ( '/' , StringComparison . Ordinal ) )
{
url = "/dmr/" + url ;
}
if ( ! url . StartsWith ( "/" ))
if ( ! url . StartsWith ( "/" , StringComparison . Ordinal ))
{
url = "/" + url ;
}
@ -954,11 +969,7 @@ namespace Emby.Dlna.PlayTo
return baseUrl + url ;
}
private TransportCommands AvCommands { get ; set ; }
private TransportCommands RendererCommands { get ; set ; }
public static async Task < Device > CreateuPnpDeviceAsync ( Uri url , IHttpClient httpClient , IServerConfigurationManager config , ILogger logger , CancellationToken cancellationToken )
public static async Task < Device > CreateuPnpDeviceAsync ( Uri url , IHttpClient httpClient , ILogger logger , CancellationToken cancellationToken )
{
var ssdpHttpClient = new SsdpHttpClient ( httpClient ) ;
@ -966,13 +977,13 @@ namespace Emby.Dlna.PlayTo
var friendlyNames = new List < string > ( ) ;
var name = document . Descendants ( uPnpNamespaces. u d. GetName ( "friendlyName" ) ) . FirstOrDefault ( ) ;
var name = document . Descendants ( UPnpNamespaces. U d. GetName ( "friendlyName" ) ) . FirstOrDefault ( ) ;
if ( name ! = null & & ! string . IsNullOrWhiteSpace ( name . Value ) )
{
friendlyNames . Add ( name . Value ) ;
}
var room = document . Descendants ( uPnpNamespaces. u d. GetName ( "roomName" ) ) . FirstOrDefault ( ) ;
var room = document . Descendants ( UPnpNamespaces. U d. GetName ( "roomName" ) ) . FirstOrDefault ( ) ;
if ( room ! = null & & ! string . IsNullOrWhiteSpace ( room . Value ) )
{
friendlyNames . Add ( room . Value ) ;
@ -981,77 +992,77 @@ namespace Emby.Dlna.PlayTo
var deviceProperties = new DeviceInfo ( )
{
Name = string . Join ( " " , friendlyNames ) ,
BaseUrl = string . Format ( "http://{0}:{1}" , url . Host , url . Port )
BaseUrl = string . Format ( CultureInfo . InvariantCulture , "http://{0}:{1}" , url . Host , url . Port )
} ;
var model = document . Descendants ( uPnpNamespaces. u d. GetName ( "modelName" ) ) . FirstOrDefault ( ) ;
var model = document . Descendants ( UPnpNamespaces. U d. GetName ( "modelName" ) ) . FirstOrDefault ( ) ;
if ( model ! = null )
{
deviceProperties . ModelName = model . Value ;
}
var modelNumber = document . Descendants ( uPnpNamespaces. u d. GetName ( "modelNumber" ) ) . FirstOrDefault ( ) ;
var modelNumber = document . Descendants ( UPnpNamespaces. U d. GetName ( "modelNumber" ) ) . FirstOrDefault ( ) ;
if ( modelNumber ! = null )
{
deviceProperties . ModelNumber = modelNumber . Value ;
}
var uuid = document . Descendants ( uPnpNamespaces. u d. GetName ( "UDN" ) ) . FirstOrDefault ( ) ;
var uuid = document . Descendants ( UPnpNamespaces. U d. GetName ( "UDN" ) ) . FirstOrDefault ( ) ;
if ( uuid ! = null )
{
deviceProperties . UUID = uuid . Value ;
}
var manufacturer = document . Descendants ( uPnpNamespaces. u d. GetName ( "manufacturer" ) ) . FirstOrDefault ( ) ;
var manufacturer = document . Descendants ( UPnpNamespaces. U d. GetName ( "manufacturer" ) ) . FirstOrDefault ( ) ;
if ( manufacturer ! = null )
{
deviceProperties . Manufacturer = manufacturer . Value ;
}
var manufacturerUrl = document . Descendants ( uPnpNamespaces. u d. GetName ( "manufacturerURL" ) ) . FirstOrDefault ( ) ;
var manufacturerUrl = document . Descendants ( UPnpNamespaces. U d. GetName ( "manufacturerURL" ) ) . FirstOrDefault ( ) ;
if ( manufacturerUrl ! = null )
{
deviceProperties . ManufacturerUrl = manufacturerUrl . Value ;
}
var presentationUrl = document . Descendants ( uPnpNamespaces. u d. GetName ( "presentationURL" ) ) . FirstOrDefault ( ) ;
var presentationUrl = document . Descendants ( UPnpNamespaces. U d. GetName ( "presentationURL" ) ) . FirstOrDefault ( ) ;
if ( presentationUrl ! = null )
{
deviceProperties . PresentationUrl = presentationUrl . Value ;
}
var modelUrl = document . Descendants ( uPnpNamespaces. u d. GetName ( "modelURL" ) ) . FirstOrDefault ( ) ;
var modelUrl = document . Descendants ( UPnpNamespaces. U d. GetName ( "modelURL" ) ) . FirstOrDefault ( ) ;
if ( modelUrl ! = null )
{
deviceProperties . ModelUrl = modelUrl . Value ;
}
var serialNumber = document . Descendants ( uPnpNamespaces. u d. GetName ( "serialNumber" ) ) . FirstOrDefault ( ) ;
var serialNumber = document . Descendants ( UPnpNamespaces. U d. GetName ( "serialNumber" ) ) . FirstOrDefault ( ) ;
if ( serialNumber ! = null )
{
deviceProperties . SerialNumber = serialNumber . Value ;
}
var modelDescription = document . Descendants ( uPnpNamespaces. u d. GetName ( "modelDescription" ) ) . FirstOrDefault ( ) ;
var modelDescription = document . Descendants ( UPnpNamespaces. U d. GetName ( "modelDescription" ) ) . FirstOrDefault ( ) ;
if ( modelDescription ! = null )
{
deviceProperties . ModelDescription = modelDescription . Value ;
}
var icon = document . Descendants ( uPnpNamespaces. u d. GetName ( "icon" ) ) . FirstOrDefault ( ) ;
var icon = document . Descendants ( UPnpNamespaces. U d. GetName ( "icon" ) ) . FirstOrDefault ( ) ;
if ( icon ! = null )
{
deviceProperties . Icon = CreateIcon ( icon ) ;
}
foreach ( var services in document . Descendants ( uPnpNamespaces. u d. GetName ( "serviceList" ) ) )
foreach ( var services in document . Descendants ( UPnpNamespaces. U d. GetName ( "serviceList" ) ) )
{
if ( services = = null )
{
continue ;
}
var servicesList = services . Descendants ( uPnpNamespaces. u d. GetName ( "service" ) ) ;
var servicesList = services . Descendants ( UPnpNamespaces. U d. GetName ( "service" ) ) ;
if ( servicesList = = null )
{
continue ;
@ -1068,10 +1079,9 @@ namespace Emby.Dlna.PlayTo
}
}
return new Device ( deviceProperties , httpClient , logger , config );
return new Device ( deviceProperties , httpClient , logger );
}
private static readonly CultureInfo UsCulture = new CultureInfo ( "en-US" ) ;
private static DeviceIcon CreateIcon ( XElement element )
{
if ( element = = null )
@ -1079,11 +1089,11 @@ namespace Emby.Dlna.PlayTo
throw new ArgumentNullException ( nameof ( element ) ) ;
}
var mimeType = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "mimetype" ) ) ;
var width = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "width" ) ) ;
var height = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "height" ) ) ;
var depth = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "depth" ) ) ;
var url = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "url" ) ) ;
var mimeType = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "mimetype" ) ) ;
var width = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "width" ) ) ;
var height = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "height" ) ) ;
var depth = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "depth" ) ) ;
var url = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "url" ) ) ;
var widthValue = int . Parse ( width , NumberStyles . Integer , UsCulture ) ;
var heightValue = int . Parse ( height , NumberStyles . Integer , UsCulture ) ;
@ -1100,11 +1110,11 @@ namespace Emby.Dlna.PlayTo
private static DeviceService Create ( XElement element )
{
var type = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "serviceType" ) ) ;
var id = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "serviceId" ) ) ;
var scpdUrl = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "SCPDURL" ) ) ;
var controlURL = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "controlURL" ) ) ;
var eventSubURL = element . GetDescendantValue ( uPnpNamespaces. u d. GetName ( "eventSubURL" ) ) ;
var type = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "serviceType" ) ) ;
var id = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "serviceId" ) ) ;
var scpdUrl = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "SCPDURL" ) ) ;
var controlURL = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "controlURL" ) ) ;
var eventSubURL = element . GetDescendantValue ( UPnpNamespaces. U d. GetName ( "eventSubURL" ) ) ;
return new DeviceService
{
@ -1116,14 +1126,7 @@ namespace Emby.Dlna.PlayTo
} ;
}
public event EventHandler < PlaybackStartEventArgs > PlaybackStart ;
public event EventHandler < PlaybackProgressEventArgs > PlaybackProgress ;
public event EventHandler < PlaybackStoppedEventArgs > PlaybackStopped ;
public event EventHandler < MediaChangedEventArgs > MediaChanged ;
public uBaseObject CurrentMediaInfo { get ; private set ; }
private void UpdateMediaInfo ( uBaseObject mediaInfo , TRANSPORTSTATE state )
private void UpdateMediaInfo ( UBaseObject mediaInfo , TransportState state )
{
TransportState = state ;
@ -1132,7 +1135,7 @@ namespace Emby.Dlna.PlayTo
if ( previousMediaInfo = = null & & mediaInfo ! = null )
{
if ( state ! = T RANSPORTSTATE. STOPPED )
if ( state ! = T ransportState. Stopped )
{
OnPlaybackStart ( mediaInfo ) ;
}
@ -1151,7 +1154,7 @@ namespace Emby.Dlna.PlayTo
}
}
private void OnPlaybackStart ( u BaseObject mediaInfo )
private void OnPlaybackStart ( U BaseObject mediaInfo )
{
if ( string . IsNullOrWhiteSpace ( mediaInfo . Url ) )
{
@ -1164,7 +1167,7 @@ namespace Emby.Dlna.PlayTo
} ) ;
}
private void OnPlaybackProgress ( u BaseObject mediaInfo )
private void OnPlaybackProgress ( U BaseObject mediaInfo )
{
if ( string . IsNullOrWhiteSpace ( mediaInfo . Url ) )
{
@ -1177,7 +1180,7 @@ namespace Emby.Dlna.PlayTo
} ) ;
}
private void OnPlaybackStop ( u BaseObject mediaInfo )
private void OnPlaybackStop ( U BaseObject mediaInfo )
{
PlaybackStopped ? . Invoke ( this , new PlaybackStoppedEventArgs
{
@ -1185,7 +1188,7 @@ namespace Emby.Dlna.PlayTo
} ) ;
}
private void OnMediaChanged ( uBaseObject old , u BaseObject newMedia )
private void OnMediaChanged ( UBaseObject old , U BaseObject newMedia )
{
MediaChanged ? . Invoke ( this , new MediaChangedEventArgs
{
@ -1194,14 +1197,17 @@ namespace Emby.Dlna.PlayTo
} ) ;
}
bool _disposed ;
/// <inheritdoc />
public void Dispose ( )
{
Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose ( bool disposing )
{
if ( _disposed )
@ -1220,9 +1226,10 @@ namespace Emby.Dlna.PlayTo
_disposed = true ;
}
/// <inheritdoc />
public override string ToString ( )
{
return string . Format ( "{0} - {1}" , Properties . Name , Properties . BaseUrl ) ;
return string . Format ( CultureInfo . InvariantCulture , "{0} - {1}" , Properties . Name , Properties . BaseUrl ) ;
}
}
}