public ChildMedia(SourceMedia source) : base(source.Name, source.Source) { if (!source.IsParent) throw new ArgumentException("Cannot make a Child of a Child."); m_Parent = source; //m_Child = true; }
public ChildMedia(SourceMedia source) : base(source.Name, source.Source) { if (!source.IsParent) { throw new ArgumentException("Cannot make a Child of a Child."); } m_Parent = source; //m_Child = true; }
/// <summary> /// Process a Rtsp DESCRIBE. /// Re-writes the Sdp.SessionDescription in a manner which contains the values of the server and not of the origional source. /// </summary> /// <param name="describeRequest">The request received from the server</param> /// <param name="source">Tje source stream to describe</param> /// <returns>A RtspMessage with a Sdp.SessionDescription in the Body and ContentType set to application/sdp</returns> internal RtspMessage ProcessDescribe(RtspMessage describeRequest, SourceMedia source) { RtspMessage describeResponse = CreateRtspResponse(describeRequest); describeResponse.SetHeader(RtspHeaders.ContentType, Sdp.SessionDescription.MimeType); //Don't cache this SDP describeResponse.SetHeader(RtspHeaders.CacheControl, "no-cache"); //describeResponse.SetHeader(RtspHeaders.Pragma, "no-cache"); //If desired you will need a way to determine when the last time the sdp was modified, could use the sessionId from the SDP or its' created property etc.) //describeResponse.SetHeader(RtspHeaders.LastModified, if (describeRequest.Location.ToString().ToLowerInvariant().Contains("live")) { describeResponse.SetHeader(RtspHeaders.ContentBase, "rtsp://" + ((IPEndPoint)m_RtspSocket.LocalEndPoint).Address.ToString() + "/live/" + source.Id + '/'); } else { describeResponse.SetHeader(RtspHeaders.ContentBase, describeRequest.Location.ToString()); } //Create a Session Description to describe the media requested using (var sessionDescription = CreateSessionDescription(source)) { //Set the body describeResponse.Body = sessionDescription.ToString(); //Clients sessionId is created from the Sdp's SessionId Line //if (string.IsNullOrWhiteSpace(SessionId)) SessionId = sessionDescription.SessionId; } //Return the resulting message return describeResponse; }
/// <summary> /// Dynamically creates a Sdp.SessionDescription for the given SourceStream using the information already present and only re-writing the necessary values. /// </summary> /// <param name="stream">The source stream to create a SessionDescription for</param> /// <returns>The created SessionDescription</returns> internal Sdp.SessionDescription CreateSessionDescription(SourceMedia stream) { if (stream == null) throw new ArgumentNullException("stream"); //else if (SessionDescription != null) throw new NotImplementedException("There is already a m_SessionDescription for this session, updating is not implemented at this time"); string sessionId = Media.Ntp.NetworkTimeProtocol.DateTimeToNptTimestamp(DateTime.UtcNow).ToString(), sessionVersion = Media.Ntp.NetworkTimeProtocol.DateTimeToNptTimestamp(DateTime.UtcNow).ToString(); string originatorString = "ASTI-Media-Server " + sessionId + " " + sessionVersion + " IN " + (m_RtspSocket.AddressFamily == AddressFamily.InterNetworkV6 ? "IP6 " : "IP4 " ) + ((IPEndPoint)m_RtspSocket.LocalEndPoint).Address.ToString(); string sessionName = "ASTI-Streaming-Session-" + stream.Name; Sdp.SessionDescription sdp; RtpClient sourceClient; if (stream is RtpSource) { RtpSource rtpSource = stream as RtpSource; //Make the new SessionDescription sdp = new Sdp.SessionDescription(rtpSource.SessionDescription.ToString()); //Remove the old connection lines if they exist while(sdp.ConnectionLine != null) sdp.Remove(sdp.ConnectionLine, false); sourceClient = rtpSource.RtpClient; } else { sdp = new Sdp.SessionDescription(0); } //Change the DocumentVersion and update the name sdp.SessionName = sessionName; //Change the DocumentVersion and update the originator sdp.OriginatorAndSessionIdentifier = originatorString; //Type = broadcast //charset string protcol = RtspMessage.MessageIdentifier.ToLowerInvariant(), controlLineBase = "a=control:" + protcol + "://" + ((IPEndPoint)(m_RtspSocket.LocalEndPoint)).Address.ToString() + "/live/" + stream.Id; //check for rtspu later... //Find an existing control line Media.Sdp.SessionDescriptionLine controlLine = sdp.ControlLine; //If there was one remove it while (controlLine != null) { sdp.Remove(controlLine); controlLine = sdp.ControlLine; } //Determine if session level control line should be present //Rewrite a new connection line string addressString = LocalEndPoint.Address.ToString();// +"/127/2"; //int lastPort = Utility.FindOpenPort( stream.m_ForceTCP ? ProtocolType.Tcp : ProtocolType.Udp); //Indicate a port in the sdp, setup should also use this port, this should essentially reserve the port for the setup process... //if (!stream.m_ForceTCP) //addressString += "/127" +'/' + lastPort + 1; //else //addressString += + ((IPEndPoint)RemoteEndPoint).Port; //Check for the existing connectionLine Sdp.Lines.SessionConnectionLine connectionLine = sdp.ConnectionLine as Sdp.Lines.SessionConnectionLine; //Add the new line if needed if (connectionLine == null) sdp.ConnectionLine = connectionLine = new Sdp.Lines.SessionConnectionLine() { ConnectionAddress = addressString, ConnectionAddressType = m_RtspSocket.AddressFamily == AddressFamily.InterNetworkV6 ? Media.Sdp.Lines.SessionConnectionLine.IP6 : Media.Sdp.Lines.SessionConnectionLine.IP4, ConnectionNetworkType = Media.Sdp.Lines.SessionConnectionLine.InConnectionToken }; IEnumerable<Sdp.SessionDescriptionLine> bandwithLines; //Indicate that the server will not accept media as input for this session //Put the attribute in the Session Description, //Should check that its not already set? //sdp.Add(new Sdp.SessionDescriptionLine("a=recvonly")); //Remove any existing session range lines, don't upate the version while (sdp.RangeLine != null) sdp.Remove(sdp.RangeLine, false); //Todo add a Range line which shows the length of this media. //Iterate the source MediaDescriptions, could just create a new one with the fmt which contains the profile level information foreach (Sdp.MediaDescription md in sdp.MediaDescriptions) { //Find a control line controlLine = md.ControlLine; //Rewrite it if present to reflect the appropriate MediaDescription while (controlLine != null) { md.Remove(controlLine); controlLine = md.ControlLine; } //Remove old bandwith lines bandwithLines = md.BandwidthLines; //Remove existing bandwidth information, should check for AS if(stream.m_DisableQOS) foreach (Sdp.SessionDescriptionLine line in bandwithLines) md.Remove(line); //Remove all other alternate information //Should probably only remove certain ones. foreach (Sdp.SessionDescriptionLine line in md.Lines.Where(l => l.Parts.Any(p => p.Contains("alt"))).ToArray()) md.Remove(line); //Add a control line for the MedaiDescription (which is `rtsp://./Id/audio` (video etc) //Should be a TrackId and not the media type to allow more then one media type to be controlled. //e.g. Two audio streams or text streams is valid. md.Add(new Sdp.SessionDescriptionLine("a=control:" + "/live/" + stream.Id + '/' + md.MediaType)); //Add the connection line for the media //md.Add(connectionLine); //Should check for Timing Info and update for playing streams if (stream.m_DisableQOS) { md.Add(Sdp.Lines.SessionBandwidthLine.DisabledSendLine); md.Add(Sdp.Lines.SessionBandwidthLine.DisabledReceiveLine); md.Add(Sdp.Lines.SessionBandwidthLine.DisabledApplicationSpecificLine); } //else //{ // //ToDo use whatever values are defined for the session's bandwidth atp // md.Add(new Sdp.SessionDescriptionLine("b=RS:140")); // md.Add(new Sdp.SessionDescriptionLine("b=RR:140")); // md.Add(new Sdp.SessionDescriptionLine("b=AS:0")); //Determine if AS needs to be forwarded //} //Should actually reflect outgoing port for this session md.MediaPort = 0; //Determine if attached and set the MediaPort. if (m_RtpClient != null) { var context = m_RtpClient.GetContextForMediaDescription(md); if (context != null) md.MediaPort = ((IPEndPoint)context.RemoteRtp).Port; //Set any other variables which may be been changed in the session } #region Independent TCP //if (!stream.m_ForceTCP) //{ // //md.MediaPort = lastPort; // //lastPort += 2; //} //else //{ // //VLC `Blows up` when this happens // //bad SDP "m=" line: m=audio 40563 TCP/RTP/AVP 96 // //md.MediaProtocol = "TCP/RTP/AVP"; // //fmt should be the same // //This mainly implies that stand-alone RTP over TCP is occuring anyway. // //Since this code supports the RtspServer this is fine for now. // //The RtpClient also deals with the framing from RTSP when used in conjunction with so.. // //This needs to be addressed in the RtpClient which allows currently allows Rtp and Rtcp to be duplexed in TCP and UDP // //but does not handle the case of TCP when a sender wants to connect with 2 seperate TCP sockets as per RFC4571. // //a=setup:passive // //a=connection:new // //The RtpClient would then need to have a RtcpSocket ready on the 'standby' just in case the remote end point connected and began sending the data. // //The other way to hanle this would be use only a single socket in both cases and change the remote endpoint = 0.... and decypher the data based on the end point... e.g. the port. //} #endregion //Verify Timing lines. //Lines should have a startTime equal the Uptime of the stream //Lines should have a stopTime equal to the EndTime of the stream. } //Top level stream control line (Should only be added if Aggregate Control of the stream is allowed. //sdp.Add(new Sdp.SessionDescriptionLine(controlLineBase)); return sdp; }