//SourceStream Implementation public override void Start() { if (m_RtpClient != null) { return; } //Create a RtpClient so events can be sourced from the Server to many clients without this Client knowing about all participants //If this class was used to send directly to one person it would be setup with the recievers address m_RtpClient = new Rtp.RtpClient(); SessionDescription = new Sdp.SessionDescription(0, "v√ƒ", Name); SessionDescription.Add(new Sdp.Lines.SessionConnectionLine() { ConnectionNetworkType = Sdp.Lines.SessionConnectionLine.InConnectionToken, ConnectionAddressType = Sdp.SessionDescription.WildcardString, ConnectionAddress = System.Net.IPAddress.Any.ToString() }); //Add a MediaDescription to our Sdp on any available port for RTP/AVP Transport using the RtpJpegPayloadType SessionDescription.Add(new Sdp.MediaDescription(Sdp.MediaType.video, 0, Rtp.RtpClient.RtpAvpProfileIdentifier, RFC2435Media.RFC2435Frame.RtpJpegPayloadType)); //Indicate control to each media description contained SessionDescription.Add(new Sdp.SessionDescriptionLine("a=control:*")); //Ensure the session members know they can only receive SessionDescription.Add(new Sdp.SessionDescriptionLine("a=sendonly")); //recvonly? //that this a broadcast. SessionDescription.Add(new Sdp.SessionDescriptionLine("a=type:broadcast")); //Add a Interleave (We are not sending Rtcp Packets becaues the Server is doing that) We would use that if we wanted to use this ImageSteam without the server. //See the notes about having a Dictionary to support various tracks m_RtpClient.TryAddContext(new Rtp.RtpClient.TransportContext(0, 1, sourceId, SessionDescription.MediaDescriptions.First(), false, 0)); //Add the control line SessionDescription.MediaDescriptions.First().Add(new Sdp.SessionDescriptionLine("a=control:trackID=1")); //Add the line with the clock rate in ms, obtained by TimeSpan.TicksPerMillisecond * clockRate //Make the thread m_RtpClient.m_WorkerThread = new System.Threading.Thread(SendPackets); m_RtpClient.m_WorkerThread.TrySetApartmentState(System.Threading.ApartmentState.MTA); //m_RtpClient.m_WorkerThread.IsBackground = true; //m_RtpClient.m_WorkerThread.Priority = System.Threading.ThreadPriority.BelowNormal; m_RtpClient.m_WorkerThread.Name = "SourceStream-" + Id; //If we are watching and there are already files in the directory then add them to the Queue if (m_Watcher != null && !string.IsNullOrWhiteSpace(base.Source.LocalPath) && System.IO.Directory.Exists(base.Source.LocalPath)) { foreach (string file in System.IO.Directory.GetFiles(base.Source.LocalPath)) { if (false == SupportedImageFormats.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) { continue; } } //If we have not been stopped already if (/*State != StreamState.Started && */ m_RtpClient.m_WorkerThread != null) { //Only ready after all pictures are in the queue Ready = true; m_RtpClient.m_WorkerThread.Start(); } } else { //We are ready Ready = true; m_RtpClient.m_WorkerThread.Start(); } base.Start(); }