using System;
using System.Diagnostics.Contracts;
using System.Text;
namespace Inspectron.HawkEye.RTSP.Messages
{
public class RtspTransport
{
public RtspTransport()
{
// Default value is true in RFC
IsMulticast = true;
LowerTransport = LowerTransportType.UDP;
Mode = "PLAY";
}
/*
RFC
Transport = "Transport" ":"
1\#transport-spec
transport-spec = transport-protocol/profile[/lower-transport]
*parameter
transport-protocol = "RTP"
profile = "AVP"
lower-transport = "TCP" | "UDP"
parameter = ( "unicast" | "multicast" )
| ";" "destination" [ "=" address ]
| ";" "interleaved" "=" channel [ "-" channel ]
| ";" "append"
| ";" "ttl" "=" ttl
| ";" "layers" "=" 1*DIGIT
| ";" "port" "=" port [ "-" port ]
| ";" "client_port" "=" port [ "-" port ]
| ";" "server_port" "=" port [ "-" port ]
| ";" "ssrc" "=" ssrc
| ";" "mode" = <"> 1\#mode <">
ttl = 1*3(DIGIT)
port = 1*5(DIGIT)
ssrc = 8*8(HEX)
channel = 1*3(DIGIT)
address = host
mode = <"> *Method <"> | Method
*/
///
/// List of transport
///
[Serializable]
public enum TransportType
{
///
/// RTP for now
///
RTP,
}
///
/// Profile type
///
[Serializable]
public enum ProfileType
{
///
/// RTP/AVP of now
///
AVP,
}
///
/// Transport type.
///
[Serializable]
public enum LowerTransportType
{
///
/// UDP transport.
///
UDP,
///
/// TCP transport.
///
TCP,
}
///
/// Gets or sets the transport.
///
/// The transport.
public TransportType Transport { get; set; }
///
/// Gets or sets the profile.
///
/// The profile.
public ProfileType Profile { get; set; }
///
/// Gets or sets the lower transport.
///
/// The lower transport.
public LowerTransportType LowerTransport { get; set; }
///
/// Gets or sets a value indicating whether this instance is multicast.
///
///
/// true if this instance is multicast; otherwise, false.
///
public bool IsMulticast { get; set; }
///
/// Gets or sets the destination.
///
/// The destination.
public string Destination { get; set; }
///
/// Gets or sets the source.
///
/// The source.
public string Source { get; set; }
///
/// Gets or sets the interleaved.
///
/// The interleaved.
public PortCouple Interleaved { get; set; }
///
/// Gets or sets a value indicating whether this instance is append.
///
/// true if this instance is append; otherwise, false.
public bool IsAppend { get; set; }
///
/// Gets or sets the TTL.
///
/// The TTL.
public int TTL { get; set; }
///
/// Gets or sets the layers.
///
/// The layers.
public int Layers { get; set; }
///
/// Gets or sets the port.
///
/// The port.
public PortCouple Port { get; set; }
///
/// Gets or sets the client port.
///
/// The client port.
public PortCouple ClientPort { get; set; }
///
/// Gets or sets the server port.
///
/// The server port.
public PortCouple ServerPort { get; set; }
///
/// Gets or sets the S SRC.
///
/// The S SRC.
public string SSrc { get; set; }
///
/// Gets or sets the mode.
///
/// The mode.
public string Mode { get; set; }
///
/// Parses the specified transport string.
///
/// A transport string.
/// The transport class.
/// is null.
public static RtspTransport Parse(string aTransportString)
{
if (aTransportString == null)
throw new ArgumentNullException("aTransportString");
Contract.EndContractBlock();
RtspTransport returnValue = new RtspTransport();
string[] transportPart = aTransportString.Split(';');
string[] transportProtocolPart = transportPart[0].Split('/');
ReadTransport(returnValue, transportProtocolPart);
ReadProfile(returnValue, transportProtocolPart);
ReadLowerTransport(returnValue, transportProtocolPart);
foreach (string part in transportPart)
{
string[] subPart = part.Split('=');
switch (subPart[0].ToUpperInvariant())
{
case "UNICAST":
returnValue.IsMulticast = false;
break;
case "MULTICAST":
returnValue.IsMulticast = true;
break;
case "DESTINATION":
if (subPart.Length == 2)
returnValue.Destination = subPart[1];
break;
case "SOURCE":
if (subPart.Length == 2)
returnValue.Source = subPart[1];
break;
case "INTERLEAVED":
returnValue.IsMulticast = false;
if (subPart.Length < 2)
throw new ArgumentException("interleaved value invalid", "aTransportString");
returnValue.Interleaved = PortCouple.Parse(subPart[1]);
break;
case "APPEND":
returnValue.IsAppend = true;
break;
case "TTL":
int ttl = 0;
if (subPart.Length < 2 || !int.TryParse(subPart[1], out ttl))
throw new ArgumentException("TTL value invalid", "aTransportString");
returnValue.TTL = ttl;
break;
case "LAYERS":
int layers = 0;
if (subPart.Length < 2 || !int.TryParse(subPart[1], out layers))
throw new ArgumentException("Layers value invalid", "aTransportString");
returnValue.TTL = layers;
break;
case "PORT":
if (subPart.Length < 2)
throw new ArgumentException("Port value invalid", "aTransportString");
returnValue.Port = PortCouple.Parse(subPart[1]);
break;
case "CLIENT_PORT":
if (subPart.Length < 2)
throw new ArgumentException("client_port value invalid", "aTransportString");
returnValue.ClientPort = PortCouple.Parse(subPart[1]);
break;
case "SERVER_PORT":
if (subPart.Length < 2)
throw new ArgumentException("server_port value invalid", "aTransportString");
returnValue.ServerPort = PortCouple.Parse(subPart[1]);
break;
case "SSRC":
if (subPart.Length < 2)
throw new ArgumentException("ssrc value invalid", "aTransportString");
returnValue.SSrc = subPart[1];
break;
case "MODE":
if (subPart.Length < 2)
throw new ArgumentException("mode value invalid", "aTransportString");
returnValue.Mode = subPart[1];
break;
default:
// TODO log invalid part
break;
}
}
return returnValue;
}
private static void ReadLowerTransport(RtspTransport returnValue, string[] transportProtocolPart)
{
if (transportProtocolPart.Length == 3)
{
LowerTransportType lowerTransport;
if (!Enum.TryParse(transportProtocolPart[2], out lowerTransport))
throw new ArgumentException("Lower transport type invalid", "aTransportString");
returnValue.LowerTransport = lowerTransport;
}
}
private static void ReadProfile(RtspTransport returnValue, string[] transportProtocolPart)
{
ProfileType profile;
if (transportProtocolPart.Length < 2 || !Enum.TryParse(transportProtocolPart[1], out profile))
throw new ArgumentException("Transport profile type invalid", "aTransportString");
returnValue.Profile = profile;
}
private static void ReadTransport(RtspTransport returnValue, string[] transportProtocolPart)
{
TransportType transport;
if (!Enum.TryParse(transportProtocolPart[0], out transport))
throw new ArgumentException("Transport type invalid", "aTransportString");
returnValue.Transport = transport;
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
StringBuilder transportString = new StringBuilder();
transportString.Append(Transport.ToString());
transportString.Append('/');
transportString.Append(Profile.ToString());
transportString.Append('/');
transportString.Append(LowerTransport.ToString());
if (LowerTransport == LowerTransportType.TCP)
{
transportString.Append(";unicast");
}
if (LowerTransport == LowerTransportType.UDP)
{
transportString.Append(';');
transportString.Append(IsMulticast ? "multicast" : "unicast");
}
if (Destination != null)
{
transportString.Append(";destination=");
transportString.Append(Destination);
}
if (Source != null)
{
transportString.Append(";source=");
transportString.Append(Source);
}
if (Interleaved != null)
{
transportString.Append(";interleaved=");
transportString.Append(Interleaved.ToString());
}
if (IsAppend)
{
transportString.Append(";append");
}
if (TTL > 0)
{
transportString.Append(";ttl=");
transportString.Append(TTL);
}
if (Layers > 0)
{
transportString.Append(";layers=");
transportString.Append(Layers);
}
if (Port != null)
{
transportString.Append(";port=");
transportString.Append(Port.ToString());
}
if (ClientPort != null)
{
transportString.Append(";client_port=");
transportString.Append(ClientPort.ToString());
}
if (ServerPort != null)
{
transportString.Append(";server_port=");
transportString.Append(ServerPort.ToString());
}
if (SSrc != null)
{
transportString.Append(";ssrc=");
transportString.Append(SSrc);
}
if (Mode != null && Mode != "PLAY")
{
transportString.Append(";mode=");
transportString.Append(Mode);
}
return transportString.ToString();
}
}
}