Files
2025-08-19 12:45:50 +02:00

368 lines
14 KiB
C#

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
*/
/// <summary>
/// List of transport
/// </summary>
[Serializable]
public enum TransportType
{
/// <summary>
/// RTP for now
/// </summary>
RTP,
}
/// <summary>
/// Profile type
/// </summary>
[Serializable]
public enum ProfileType
{
/// <summary>
/// RTP/AVP of now
/// </summary>
AVP,
}
/// <summary>
/// Transport type.
/// </summary>
[Serializable]
public enum LowerTransportType
{
/// <summary>
/// UDP transport.
/// </summary>
UDP,
/// <summary>
/// TCP transport.
/// </summary>
TCP,
}
/// <summary>
/// Gets or sets the transport.
/// </summary>
/// <value>The transport.</value>
public TransportType Transport { get; set; }
/// <summary>
/// Gets or sets the profile.
/// </summary>
/// <value>The profile.</value>
public ProfileType Profile { get; set; }
/// <summary>
/// Gets or sets the lower transport.
/// </summary>
/// <value>The lower transport.</value>
public LowerTransportType LowerTransport { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is multicast.
/// </summary>
/// <value>
/// <c>true</c> if this instance is multicast; otherwise, <c>false</c>.
/// </value>
public bool IsMulticast { get; set; }
/// <summary>
/// Gets or sets the destination.
/// </summary>
/// <value>The destination.</value>
public string Destination { get; set; }
/// <summary>
/// Gets or sets the source.
/// </summary>
/// <value>The source.</value>
public string Source { get; set; }
/// <summary>
/// Gets or sets the interleaved.
/// </summary>
/// <value>The interleaved.</value>
public PortCouple Interleaved { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is append.
/// </summary>
/// <value><c>true</c> if this instance is append; otherwise, <c>false</c>.</value>
public bool IsAppend { get; set; }
/// <summary>
/// Gets or sets the TTL.
/// </summary>
/// <value>The TTL.</value>
public int TTL { get; set; }
/// <summary>
/// Gets or sets the layers.
/// </summary>
/// <value>The layers.</value>
public int Layers { get; set; }
/// <summary>
/// Gets or sets the port.
/// </summary>
/// <value>The port.</value>
public PortCouple Port { get; set; }
/// <summary>
/// Gets or sets the client port.
/// </summary>
/// <value>The client port.</value>
public PortCouple ClientPort { get; set; }
/// <summary>
/// Gets or sets the server port.
/// </summary>
/// <value>The server port.</value>
public PortCouple ServerPort { get; set; }
/// <summary>
/// Gets or sets the S SRC.
/// </summary>
/// <value>The S SRC.</value>
public string SSrc { get; set; }
/// <summary>
/// Gets or sets the mode.
/// </summary>
/// <value>The mode.</value>
public string Mode { get; set; }
/// <summary>
/// Parses the specified transport string.
/// </summary>
/// <param name="aTransportString">A transport string.</param>
/// <returns>The transport class.</returns>
/// <exception cref="ArgumentNullException"><paramref name="aTransportString"/> is null.</exception>
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<LowerTransportType>(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<ProfileType>(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<TransportType>(transportProtocolPart[0], out transport))
throw new ArgumentException("Transport type invalid", "aTransportString");
returnValue.Transport = transport;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
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();
}
}
}