/// <summary> /// Deep clone /// </summary> public object Clone() { NetStreamStatusEvent clone = new NetStreamStatusEvent(); clone.Event = Event; clone.Code = Code; clone.Level = Level; clone.EventInfo = (AMFObject)EventInfo.Clone(); return(clone); }
protected void NS_OnStatus(object sender, NetStreamStatusEvent netStreamStatusEvent) { NetStreamHelper netStreamHelper = FindNetStreamHelper(sender as NetStream); if (netStreamHelper != null) { switch (netStreamStatusEvent.Code) { case "NetStream.Play.Stop": // start buffering next mediaitem? if (!netStreamHelper.NetStream.SeekIsActive && !netStreamHelper.IsComplete) { commandInProgress = false; // reset it netStreamHelper.IsComplete = true; } // possible button state changed DoEvent_MP_OnControleButtonStateChange(OnControleButtonStateChange, this); break; case "NetStream.Play.OnMetaData": lock (lockVAR) { netStreamHelper.Item.NetStreamDurationInMS = Convert.ToInt64(netStreamHelper.NetStream.Duration * 1000); } break; case "NetStream.Play.Start": case "NetStream.Play.Resume": failedPlayCount = 0; // reset commandInProgress = false; // reset it after Play command // Do not set PlayState from Seek to Playing, otherwise // call to "StartPlayingAudioChannel" won't start playing audio again! // "StartPlayingAudioChannel" is called from "NC_OnMediaPacket" // so playing will start when there is data in the buffer MP_OnMediaItem onMediaItemSeekEnd = null; MediaItem item = null; lock (lockVAR) { if (netStreams.Count > 0 && netStreams[0].PlayState == NetStreamState.Seek) { if (OnMediaItemSeekEnd != null) { // We're playing onMediaItemSeekEnd = OnMediaItemSeekEnd; item = (MediaItem)netStreams[0].Item.Clone(); } } } //lock DoEvent_MP_OnMediaItem(onMediaItemSeekEnd, this, item); // possible button state changed DoEvent_MP_OnControleButtonStateChange(OnControleButtonStateChange, this); break; case "NetStream.Seek.Notify": // wait for "NetStream.Play.Start" // Flush buffer once more (because packets could be stored between call en send to remote server if (netStreamHelper.Buffer != null) { netStreamHelper.Buffer.Clear(); } // Should already be set to this! netStreamHelper.PlayState = NetStreamState.Seek; // possible button state changed DoEvent_MP_OnControleButtonStateChange(OnControleButtonStateChange, this); break; case "NetStream.Pause.Notify": commandInProgress = false; // reset it after seek command // possible button state changed DoEvent_MP_OnControleButtonStateChange(OnControleButtonStateChange, this); break; case "NetStream.Play.Failed": // event when playing fails and we have to skip to the next one case "NetStream.Play.StreamNotFound": case "NetStream.Failed": failedPlayCount++; // Fake status so Next and stop work lock (lockVAR) { if (netStreams.Count == 1) { netStreams[0].Item.SkipBecauseOfError = true; netStreams[0].PlayState = NetStreamState.Playing; } else if (netStreams.Count > 1) { NetStreamHelper nsh = netStreams[netStreams.Count - 1]; netStreams.RemoveAt(netStreams.Count - 1); netStreams[netStreams.Count - 1].NextNetStreamStarted = false; nsh.Item.SkipBecauseOfError = true; CloseAudioStream(nsh); MPThread_CheckForPreBuffering(); break; } } //lock if (currentPlaylist.NextMediaItemIndex != -1 && failedPlayCount <= 10) { // Continue with next one if there is one! MPThread_Next(); } else { // stop playing, 10 consecutive fails MPThread_Stop(); } break; } //switch } }
/// <summary> /// Deep clone /// </summary> public object Clone() { NetStreamStatusEvent clone = new NetStreamStatusEvent(); clone.Event = Event; clone.Code = Code; clone.Level = Level; clone.EventInfo = (AMFObject)EventInfo.Clone(); return clone; }
[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; }
private void NS_OnStatus(object sender, NetStreamStatusEvent netStreamStatusEvent) { if (netStreamStatusEvent.Code == "NetStream.Play.Complete") { Console.WriteLine("RTMP NetStream has ended sending data. (Audio playing will stop some time later)"); } }