[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        internal void PostMessage(MQ_RTMPMessage message, bool waitForEmptyQueue = false, int timeOutinMS = -1)
        {
            if (waitForEmptyQueue)
            {
                // Wait before posting that the messagequeue is empty
                DateTime timeStamp = DateTime.Now;
                while (true)
                {
                    lock (lockVAR)
                    {
                        if (messageQueue == null || messageQueue.Count == 0)
                        {
                            break;
                        }
                    }//lock
                    Thread.Sleep(10);
                    if (timeOutinMS >= 0 && (DateTime.Now - timeStamp).TotalMilliseconds >= timeOutinMS)
                    {
                        // we exiten because of timeout
                        break;
                    }
                }//
            }

            if (message != null)
            {
                AddMessageToPump(message);
            }
        }
        /// <summary>
        /// Create a logical channel for message communication for use
        /// in publishing of audio or video and metadata carrying
        /// </summary>
        /// <returns></returns>
        public void CreateStream(NetStream ns)
        {
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.CreateStream;
            message.Params = new object[] { ns }; ;

            AddMessageToPump(message);
        }
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        internal void DeleteStream(int stream_id)
        {
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.DeleteStream;
            message.Params = new object[] { stream_id }; ;

            AddMessageToPump(message);
        }
        /// <summary>
        /// Make connection with a RTMP server like Wowza, red5 or FMS
        /// </summary>
        /// <returns></returns>
        public void Connect(ServerLink serverLink, NC_ResultCallBackConnect resultCallBackConnect, params AMFObjectProperty[] amfProperties)
        {
            // First check if there isn't a build connection in the message queue
            lock (lockVAR)
            {
                if (messageQueue != null)
                {
                    foreach (MQ_RTMPMessage msg in messageQueue)
                    {
                        if (msg.MethodCall == MethodCall.ConnectRTMPServer)
                        {
                            // cancel, we're already trying to do it!
                            return;
                        }
                    } //foreach
                }
            } //lock

            netConnectionConnectInfo.Clear();

            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.ConnectRTMPServer;
            message.Params = new object[] { serverLink, resultCallBackConnect, amfProperties };

            AddMessageToPump(message);
        }
        public void CloseConnection()
        {
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.CloseConnectionRTMPServer;
            message.Params = null;

            AddMessageToPump(message);
        }
 /// <summary>
 /// Add new message to queue. Thread safe
 /// </summary>
 private void AddMessageToPump(MQ_RTMPMessage message)
 {
     lock (lockVAR)
     {
         if (messageQueue != null)
         {
             messageQueue.Add(message);
         }
     } //lock
 }
示例#7
0
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        virtual internal bool HandleOnMediaPacket(RTMPPacket packet)
        {
            if (blockMediaPackets > 0)
            {
                LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] blockingMediaPacket Timestamp : {0}, Size : {0}", TimeSpan.FromMilliseconds(packet.TimeStamp), packet.BodySize));
                return true;
            }

            mediaChannel = packet.Channel; //need for pause to have lastest timestamp stored in NetConnection."channelTimestamp" 

            LastMediaPacket = packet;
            TimeStamp = TimeSpan.FromMilliseconds(packet.TimeStamp);

            if (packet.PacketType == PacketType.Audio)
            {
                if (packet.BodySize <= 1)
                {
                    LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Ignoring too small audio packet: size: {0}", packet.BodySize));
                    return true;
                }

                // Store audio data in audio buffer
                int offset = 1;
                if (syncAfterPauseNeeded)
                {
                    LibRTMPLogger.Log(LibRTMPLogLevel.Info, "[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Unpause event code started");

                    // Match last audio packet with this packet (must both be atleast 10 bytes big otherwhise match 
                    // will be bad
                    if (packet.BodySize > 10 && lastAudioPacket.Length > 10)
                    {
                        byte[] pattern = new byte[10];
                        Buffer.BlockCopy(packet.Body, 1, pattern, 0, 10);
                        LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Duplicate data, packetsize={0}", packet.BodySize - 1));

                        int[] hits = lastAudioPacket.Locate(pattern);
                        if (hits.Length > 0)
                        {
                            LibRTMPLogger.Log(LibRTMPLogLevel.Info, "[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Duplicate data detected");
                            // free data
                            savedPackets = null;
                            syncAfterPauseNeeded = false; // we're in sync

                            // we only look at the first hit, and try to match it up with as much 
                            // data as we have in "packet.body[1]" (this is start of pattern)
                            int j = hits[0];
                            // set offset so, it matches the entire packet!
                            offset = (int)packet.BodySize - 1;
                            for (int i = 1; i < packet.BodySize; i++)
                            {
                                if (j >= lastAudioPacket.Length || packet.Body[i] != lastAudioPacket[j])
                                {
                                    // New offset for packet data, where new data starts
                                    offset = i;
                                    // we're ready
                                    break;
                                }
                                j++;
                            } //for

                            // remove unused data from lastAudioPacket (or all)
                            if (offset >= (lastAudioPacket.Length - 1))
                            {
                                lastAudioPacket = null;
                            }
                            else
                            {
                                // there is some data left
                                int left = (lastAudioPacket.Length - 1) - offset;
                                byte[] leftB = new byte[left];
                                Buffer.BlockCopy(lastAudioPacket, j, leftB, 0, left);
                                // make sure we run this routine also for the next packet
                                lock (lockVAR)
                                {
                                    syncAfterPauseNeeded = true;
                                } //lock
                            }

                            LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Duplicate data detected up till offset:  {0}", offset));
                        }
                        else
                        {
                            LibRTMPLogger.Log(LibRTMPLogLevel.Info, "[CDR.LibRTMP.NetStream.HandleOnMediaPacket] NO Duplicate data detected");
                            if (savedPackets == null)
                            {
                                savedPackets = new List<RTMPPacket>();
                            }
                            savedPackets.Add(packet);

                            // After 10 packets received , just quit trying!
                            if (savedPackets.Count >= 10)
                            {
                                ReplaySavedPackets();
                            }
                            
                            return true;
                        }
                    }
                } // if got unpause event

                if (offset >= (int)packet.BodySize - 1)
                {
                    int newSize = (int)packet.BodySize - 1;
                    LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Duplicate data, skipped entire packet (size={0})", newSize));
                    // no data left to work with. so skip this packet
                    return true;
                }

                msAudioBuffer.Write(packet.Body, offset, (int)packet.BodySize - offset);
                mediaBytesReceived += packet.BodySize;

                // lastAudioPacket is needed to rematch data after a pause (streaming server 
                // seems to send the same packet and manipulation of position doesn't seem the fix it)
                // small optimalization (most of the time packets are of the same size!
                if (lastAudioPacket == null || lastAudioPacket.Length != (packet.BodySize - 1))
                {
                    lastAudioPacket = new byte[packet.BodySize - 1];
                }
                Buffer.BlockCopy(packet.Body, 1, lastAudioPacket, 0, (int)(packet.BodySize - 1));

                if ((atBeginOfAudio && msAudioBuffer.Position >= 8192) || (!atBeginOfAudio && msAudioBuffer.Position > 0))
                {
                    atBeginOfAudio = false;
                    byte[] tmpBuffer = new byte[msAudioBuffer.Position];
                    Buffer.BlockCopy(msAudioBuffer.GetBuffer(), 0, tmpBuffer, 0, Convert.ToInt32(msAudioBuffer.Position));
                    // Reset position to start from beginning
                    msAudioBuffer.Position = 0;

                    Internal_OnAudioPacket(TimeStamp, tmpBuffer);
                    if (OnAudioPacket != null)
                    {
                        MQ_RTMPMessage message = new MQ_RTMPMessage();
                        message.MethodCall = MethodCall.OnEventCallUserCode;
                        message.Params = new object[] { OnAudioPacket, this, TimeStamp, tmpBuffer.Clone() };
                        netConnection.PostOnEventUserCallCodeMessage(message);
                    }
                }

                return true;
            }
            else if (OnVideoPacket != null && packet.PacketType == PacketType.Video)
            {
                // skip video info/command packets
                if (packet.BodySize == 2 && ((packet.Body[0] & 0xf0) == 0x50))
                {
                    return true;
                }
                else if (packet.BodySize <= 5)
                {
                    LibRTMPLogger.Log(LibRTMPLogLevel.Info, string.Format("[CDR.LibRTMP.NetStream.HandleOnMediaPacket] Ignoring too small video packet: size: {0}", packet.BodySize));
                    return true;
                }
                else
                {
                    // TODO
                    // Probaly when using pause/unpause the first packet contains data which we already got
                    // should check for this and repair as done in audio part

                    // Store video data in buffer
                    msVideoBuffer.Write(packet.Body, 1, (int)packet.BodySize - 1);

                    if (OnVideoPacket != null)
                    {
                        MQ_RTMPMessage message = new MQ_RTMPMessage();
                        message.MethodCall = MethodCall.OnEventCallUserCode;
                        message.Params = new object[] { OnVideoPacket, this, TimeStamp, msVideoBuffer.ToArray().Clone() };
                        netConnection.PostOnEventUserCallCodeMessage(message);
                    }

                    // Clear Buffer again
                    msVideoBuffer.Seek(0, SeekOrigin.Begin);
                    msVideoBuffer.SetLength(0);

                    return true;
                }
            }

            return false;
        }
        private void MQ_Connect(ServerLink sl, NC_ResultCallBackConnect onResult, params AMFObjectProperty[] amfProperties)
        {
            MQ_Close();

            netConnectionState = NetConnectionState.Connecting;
            serverLink = sl;
            bool success = MQInternal_MakeConnection(amfProperties);
            if (success)
            {
                netConnectionState = NetConnectionState.Connected;
            }

            if (success)
            {
                success = false;

                // Now we have to wait for the "onConnect" event to be send by the wowza server, before we can say the
                // connection was successful. We do this for a max of 7 seconds, if no "onConnect" then
                // disconnect and say failed
                DateTime timeStamp = DateTime.Now.AddMilliseconds(onConnectWaitTimeoutMS);
                while (!success && (timeStamp - DateTime.Now).TotalMilliseconds > 0)
                {
                    if (netConnectionState == NetConnectionState.Connected)
                    {
                        if (MQInternal_IsConnected)
                        {
                            if (MQInternal_DataInSocket)
                            {
                                RTMPPacket packet = null;
                                ReadPacket(out packet);
                                // When we get an Invoke while connecting this is the "connect" event!
                                // where we have been waiting for.
                                if (packet.PacketType == PacketType.Invoke)
                                {
                                    success = true;
                                }

                                HandleClientPacket(packet);
                            }
                        }
                        else
                        {
                            // There is no connection anymore
                            break;
                        }
                    }
                    // don't use cpu 100%
                    if (!success)
                    {
                        Thread.Sleep(10);
                    }
                } //while

                // Close connection when failed!
                if (!success || (DateTime.Now - timeStamp).TotalMilliseconds > 0)
                {
#if SSL
                    if (sslStream != null)
                    {
                        try
                        {
                            sslStream.Close();
                            sslStream.Dispose();
                        }
                        catch { }
                    }
                    sslStream = null;
#endif
                    if (tcpSocket != null)
                    {
                        try
                        {
                            tcpSocket.Shutdown(SocketShutdown.Both);
                            tcpSocket.Close();
                        }
                        catch { }
                    }
                    tcpSocket = null;

                    // temporary before we set the state to disconnected!
                    netConnectionState = NetConnectionState.Connecting;
                    dtNetConnectionKeepAlive = DateTime.Now;
                }
            }

            if (onResult != null)
            {
                // this is delegate given when connecting (used by Mediaplayer class)
                // makes event OnConnect not needed
                DoNC_ResultCallBackConnectEvent(onResult, success);
            }

            // Now we do a "global" onConnect
            if (success && OnConnect != null)
            {
                MQ_RTMPMessage message = new MQ_RTMPMessage();
                message.MethodCall = MethodCall.OnEventCallUserCode;
                message.Params = new object[] { OnConnect, this };
                AddOnEventUserCallCodeToPump(message);
            }

            if (!success)
            {
                // Set state
                netConnectionState = NetConnectionState.Disconnected;
            }
        }
        private void MQ_Close()
        {
            lock (lockVAR)
            {
                // delete all streams if there were any
                bool wasConnected = (tcpSocket != null && netConnectionState == NetConnectionState.Connected);
                if (MQInternal_IsConnected)
                {
                    foreach (NetStream netStream in netStreamsList)
                    {
                        if (netStream.Stream_ID >= 0)
                        {
                            MQ_SendDeleteStream(netStream.Stream_ID);
                            // this will generate result packets but we're cclosing the
                            // connect. Really we should wait to get all result before disconnecting
                        }
                    } //foreach
                }

#if SSL
                if (sslStream != null)
                {
                    try
                    {
                        sslStream.Close();
                        sslStream.Dispose();
                    }
                    catch { }
                }
                sslStream = null;
#endif
                if (tcpSocket != null)
                {
                    try
                    {
                        tcpSocket.Shutdown(SocketShutdown.Both);
                        tcpSocket.Close();
                    }
                    catch { }
                }
                tcpSocket = null;
                netConnectionState = NetConnectionState.Disconnected;
                dtNetConnectionKeepAlive = DateTime.MaxValue;

                receiveTimeoutMS = RTMPConst.TIMEOUT_RECEIVE;

                InChunkSize = RTMPConst.RTMP_DEFAULT_CHUNKSIZE;
                outChunkSize = RTMPConst.RTMP_DEFAULT_CHUNKSIZE;

                bwCheckCounter = 0;
                clientBW = 2500000;
                clientBW2 = 2;
                serverBW = 2500000;
                bytesReadTotal = 0;
                lastSentBytesRead = 0;
                numInvokes = 0;

                for (int i = 0; i < RTMPConst.RTMP_CHANNELS; i++)
                {
                    vecChannelsIn[i] = null;
                    vecChannelsOut[i] = null;
                    channelTimestamp[i] = 0;
                } //for

                methodCallDictionary.Clear();
                dMethodLookup.Clear();

                if (wasConnected)
                {
                    foreach (NetStream netStream in netStreamsList)
                    {
                        netStream.internal_NetStreamDisconnectNotify();
                        //
                    } //foreach

                    if (OnDisconnect != null)
                    {
                        MQ_RTMPMessage message = new MQ_RTMPMessage();
                        message.MethodCall = MethodCall.OnEventCallUserCode;
                        message.Params = new object[] { OnDisconnect, this };
                        AddOnEventUserCallCodeToPump(message);
                    }
                }

                // reset is for the next connect
                DisconnectEventSend = false;
            } //lock
        }
示例#10
0
        public void Pause(bool doPause)
        {
            if (!CheckConnection())
            {
                return;
            }

            pauseIsActive = true;
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.Pause;
            message.Params = new object[] { this, doPause };

            netConnection.PostMessage(message, true);
        }
示例#11
0
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        virtual protected bool Internal_HandleOnStatusDecoded(RTMPPacket packet, string eventStr, string codeStr, string levelStr, AMFObject obj)
        {
            //LibRTMPLogger.Log(LibRTMPLogLevel.Error, string.Format("[CDR.LibRTMP.NetStream.Internal_HandleOnStatusDecoded] event={0} code={1} level={2} Timestamp={3}", eventStr, codeStr, levelStr, packet.TimeStamp));
            //Console.WriteLine(string.Format("event={0} code={1} level={2} Timestamp={3} seekIsActive={4}", eventStr, codeStr, levelStr, packet.TimeStamp, seekIsActive.ToString()));

            if (OnStatus != null)
            {
                NetStreamStatusEvent netStreamStatusEvent = new NetStreamStatusEvent();
                netStreamStatusEvent.Clear();
                netStreamStatusEvent.Event = eventStr;
                netStreamStatusEvent.Code = codeStr;
                netStreamStatusEvent.Level = levelStr;
                netStreamStatusEvent.EventInfo = (AMFObject)obj.Clone(); // for thread safety

                MQ_RTMPMessage message = new MQ_RTMPMessage();
                message.MethodCall = MethodCall.OnEventCallUserCode;
                message.Params = new object[] { OnStatus, this, netStreamStatusEvent };
                netConnection.PostOnEventUserCallCodeMessage(message);
            }

            // Make sure we point to the right record which is buffered!
            if (codeStr == "NetStream.Play.Switch")
            {
                // end of stream (adjust duration to correct for inaccuracy!)
                lock (lockVAR)
                {
                    seekIsActive = false;
                } //lock
            }

            // Now do our thing
            switch (codeStr)
            {
                // We need to flush the existing buffers and wait until 
                // new data arrives
                case "NetStream.Seek.Notify":
                    lock (lockVAR)
                    {
                        seekIsActive = true; // is probably already set
                        blockMediaPackets++;
                        deltaTimeStampInMS = packet.TimeStamp;
                    }

                    Internal_OnSeekNotify(packet.TimeStamp);
                    break;

                case "NetStream.Play.Reset": // send when playlist starts at the beginning
                    lock (lockVAR)
                    {
                        atBeginOfAudio = true;
                        mediaBytesReceived = 0;
                        deltaTimeStampInMS = 0;
                    } //lock
                    break;

                case "NetStream.Play.Switch":
                    // Tell we have to stop playing (and drain the buffers!)
                    if (mediaBytesReceived > 0) // only when we are streaming already
                    {
                        blockMediaPackets++;
                    }
                    break;
                case "NetStream.Data.Start":
                    mediaBytesReceived = 0;
                    break;

                // stream begins to play (that is data is send)
                // deblock if needed
                case "NetStream.Play.Start":
                    lock (lockVAR)
                    {
                        if (blockMediaPackets > 0)
                        {
                            blockMediaPackets--;
                        }
                        seekIsActive = false; // is probably already set
                    } //lock
                    break;
                case "NetStream.Play.Stop":
                    ReplaySavedPackets(); // needed in case packets where saved (we're at the end so a byte sync will not occure anymore)
                    lock (lockVAR)
                    {
                        atBeginOfAudio = true;
                    }
                    break;

                // Pause logic
                case "NetStream.Pause.Notify":
                    ReplaySavedPackets(); // needed in case packets where saved (we're at the end so a byte sync will not occure anymore)
                    lock (lockVAR)
                    {
                        if (mediaBytesReceived > 0) // we're buffering
                        {
                            pauseIsActive = true;
                            Internal_OnPauseStream(true);
                            if (OnPauseStream != null)
                            {
                                MQ_RTMPMessage message = new MQ_RTMPMessage();
                                message.MethodCall = MethodCall.OnEventCallUserCode;
                                message.Params = new object[] { OnPauseStream, this, true };
                                netConnection.PostOnEventUserCallCodeMessage(message);
                            }
                        }
                    } //lock
                    break;
                case "NetStream.Unpause.Notify":
                    lock (lockVAR)
                    {
                        syncAfterPauseNeeded = true;
                        pauseIsActive = false;
                        Internal_OnPauseStream(false);
                        if (OnPauseStream != null)
                        {
                            MQ_RTMPMessage message = new MQ_RTMPMessage();
                            message.MethodCall = MethodCall.OnEventCallUserCode;
                            message.Params = new object[] { OnPauseStream, this, false };
                            netConnection.PostOnEventUserCallCodeMessage(message);
                        }
                    } //lock
                    break;

                case "NetStream.Play.Failed":
                case "NetStream.Play.StreamNotFound":
                case "NetStream.Failed":
                    break;
                case "NetStream.Play.Complete": // all data is send
                    lock (lockVAR)
                    {
                        seekIsActive = false; // safety
                    }
                    break;

            } //switch

            // Code can be eg:
            // "NetStream.Failed"
            // "NetStream.Play.Failed" 
            // "NetStream.Play.StreamNotFound" 
            // "NetConnection.Connect.InvalidApp"
            // "NetStream.Play.Start"
            // "NetStream.Publish.Start"
            // "NetStream.Play.Complete" //audio
            // "NetStream.Play.Stop"     // audio
            // "NetStream.Pause.Notify"
            // "NetStream.Seek.Notify"

            return true;
        }
示例#12
0
        virtual public void Seek(long positionInMS)
        {
            if (!CheckConnection() && seekIsActive)
            {
                return;
            }

            seekIsActive = true;
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.Seek;
            message.Params = new object[] { this, positionInMS };

            netConnection.PostMessage(message);
        }
示例#13
0
        public void CloseStream()
        {
            // Only needed when there is a valid stream
            if (stream_id < 0)
            {
                return;
            }

            if (!CheckConnection())
            {
                return;
            }

            // needed to make sure the channel wil start streaming again when a new play command
            // is send (verry important!)
            if (pauseIsActive)
            {
                Pause(false);
            }

            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.CloseStream;
            message.Params = new object[] { this };

            netConnection.PostMessage(message);
        }
示例#14
0
        public virtual void Play(string mediaFile, int start, int lenToPlay, bool resetPlayList, AMFObjectProperty properties)
        {
            if (!CheckConnection())
            {
                return;
            }

            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.Play;
            message.Params = new object[] { this, mediaFile, start, lenToPlay, resetPlayList, properties };

            netConnection.PostMessage(message);
            
        }
示例#15
0
 [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
 internal void PostOnEventUserCallCodeMessage(MQ_RTMPMessage message)
 {
     AddOnEventUserCallCodeToPump(message);
 }
示例#16
0
        /// <summary>
        /// Handle when we detect remote server is disconnected
        /// </summary>
        private void RemoteServerDisconnected()
        {
            // Handle disconnect by sending event (once) and resetting everything!
            if (!DisconnectEventSend)
            {
                DisconnectEventSend = true;
                // we do a disconnect by using the message pump makes it cleaner
                MQ_RTMPMessage message = new MQ_RTMPMessage();
                message.MethodCall = MethodCall.RemoteDisconnect;

                AddMessageToPump(message);
            }
        }
示例#17
0
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        internal void SendPing(short nType, uint nObject, uint nTime)
        {
            MQ_RTMPMessage message = new MQ_RTMPMessage();
            message.MethodCall = MethodCall.SendPing;
            message.Params = new object[] { nType, nObject, nTime };

            AddMessageToPump(message);
        }
示例#18
0
        /// <summary>
        /// After this, this class is not useable again. You need to create a new one!
        /// </summary>
        public void Close()
        {
            try
            {
                // prevent continues recurve callback
                if (closeCalled)
                {
                    return;
                }
                closeCalled = true;

                for (int i = netStreams.GetLowerBound(0); i < netStreams.GetUpperBound(0); i++)
                {
                    if (netStreams[i] != null)
                    {
                        netStreams[i].Close();
                        netStreams[i] = null;
                    }
                } //for
                netStreamsList.Clear();
                // Fire event

                if (OnDisconnect != null)
                {
                    // We have to explcitly start this event, because after this
                    // the thread will be killed!
                    MQ_RTMPMessage message = new MQ_RTMPMessage();
                    message.MethodCall = MethodCall.OnEventCallUserCode;
                    message.Params = new object[] { OnDisconnect, this };

                    SynchronizationContext sc;
                    lock (lockVAR)
                    {
                        sc = synchronizationContext;
                    } //lock
                    if (sc != null)
                    {
                        sc.Send(HandleOnEventCallUserCode, message);
                    }
                    else
                    {
                        HandleOnEventCallUserCode(message);
                    }
                }
            }
            catch (Exception e)
            {
                LibRTMPLogger.LogError(e);
            }

            KillThread();
        }
示例#19
0
        /// <summary>
        /// Needed especially for OnEventUserCallCode. We want the user code to get
        /// the event as soon as possible. Because of lock we need to call it from
        /// the messagepump (then the usercode can call the NetLibRTMP code
        /// wihtout locking problems
        /// </summary>
        private void AddOnEventUserCallCodeToPump(MQ_RTMPMessage message)
        {
            if (message.MethodCall != MethodCall.OnEventCallUserCode)
            {
                return;
            }

            lock (lockVAR)
            {
                if (messageQueue == null)
                {
                    return;
                }

                // Add as "last" OnEventUserCallCode but before rother events
                for (int i = 0; i < messageQueue.Count; i++)
                {
                    if (messageQueue[i].MethodCall != MethodCall.OnEventCallUserCode)
                    {
                        // added it before [i] and return. We're ready
                        messageQueue.Insert(i, message);
                        return;
                    }
                } //for

                // It's probably the first message which is inserted
                messageQueue.Add(message);
            } //lock
        }
示例#20
0
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] // hide it for code completion
        virtual internal bool HandleOnID3(AMFObject obj)
        {
            LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "[CDR.LibRTMP.NetConnection.NetStream.HandleOnID3]");
            obj.Dump();
            audioMetaData.Clear();
            audioMetaData.Valid = true;
            List<AMFObjectProperty> props = new List<AMFObjectProperty>();

            props.Clear();
            obj.FindMatchingProperty("v1SongTitle", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.SongTitle = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1LeadArtist", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.LeadArtist = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1AlbumTitle", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.AlbumTitle = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1YearReleased", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.YearReleased = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1SongComment", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.SongComment = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1SongGenre", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.SongGenre = props[0].StringValue;
            }
            props.Clear();
            obj.FindMatchingProperty("v1TrackNumberOnAlbum", props, 1);
            if (props.Count > 0)
            {
                audioMetaData.TrackNumberOnAlbum = props[0].StringValue;
            }


            // handle event
            if (OnID3 != null)
            {
                MQ_RTMPMessage message = new MQ_RTMPMessage();
                message.MethodCall = MethodCall.OnEventCallUserCode;
                message.Params = new object[] { OnID3, this, (AudioMetaData)audioMetaData.Clone(), obj };
                netConnection.PostOnEventUserCallCodeMessage(message);
            }

            return true;
        }