public override bool Seek(double absoluteTimestamp) { #if PARALLEL OutStreams.AsParallel().ForAll(x => { if (!x.InStream.SignalSeek(ref absoluteTimestamp)) { Logger.WARN("Unable to signal seek on an outbound stream"); } }); #else foreach ( var baseOutStream in OutStreams.Where( baseOutStream => !baseOutStream.SignalSeek(ref absoluteTimestamp))) { Logger.WARN("Unable to signal seek on an outbound stream"); } #endif if (!SignalSeek(ref absoluteTimestamp)) { Logger.FATAL("Unable to signal seek"); return(false); } return(true); }
public override bool Stop() { if (!SignalStop()) { Logger.FATAL("Unable to signal stop"); return(false); } #if PARALLEL OutStreams.AsParallel().ForAll(x => { if (!x.InStream.SignalStop()) { Logger.WARN("Unable to signal stop on an outbound stream"); } }); #else foreach ( var baseOutStream in OutStreams.Where( baseOutStream => !baseOutStream.SignalStop())) { Logger.WARN("Unable to signal stop on an outbound stream"); } #endif return(true); }
public bool Link(IOutStream pOutStream, bool reverseLink = true) { if (!pOutStream.IsCompatibleWithType(Type) || !IsCompatibleWithType(pOutStream.Type)) { Logger.FATAL("stream type {0} not compatible with stream type {1}", Type.TagToString(), pOutStream.Type.TagToString()); return(false); } if (OutStreams.Contains(pOutStream)) { Logger.WARN("BaseInStream::Link: This stream is already linked"); return(true); } OutStreams.Add(pOutStream); if (reverseLink) { if (!pOutStream.Link(this, false)) { Logger.FATAL("BaseInStream::Link: Unable to reverse link"); //NYIA; return(false); } } SignalOutStreamAttached(pOutStream); return(true); }
public override bool Play(double absoluteTimestamp, double length) { if (!SignalPlay(ref absoluteTimestamp, ref length)) { Logger.FATAL("Unable to signal play"); return(false); } #if PARALLEL OutStreams.AsParallel().ForAll(x => { if (!x.InStream.SignalPlay(ref absoluteTimestamp, ref length)) { Logger.WARN("Unable to signal play on an outbound stream"); } }); #else foreach ( var baseOutStream in OutStreams.Where( baseOutStream => !baseOutStream.SignalPlay(ref absoluteTimestamp, ref length))) { Logger.WARN("Unable to signal play on an outbound stream"); } #endif return(true); }
public void Start(Peer peer, uint publisherId, FlowWriter controller) { if (PublisherId != 0) { if (controller != null) { controller.WriteStatusResponse("Publish.BadName", Name + "is already published"); } } PublisherId = publisherId; //string error; //if (!peer.OnPublish(this, out error)) //{ // if (String.IsNullOrEmpty(error)) error = "Not allowed to publish " + Name; //} _publisher = peer; _controller = controller; _firstKeyFrame = false; foreach (var baseOutStream in OutStreams.OfType <IOutNetStream>()) { baseOutStream.SendPublishNotify(); } if (controller != null) { controller.WriteStatusResponse("Publish.Start", Name + "is now published"); } }
public bool UnLink(IOutStream pOutStream) { OutStreams.Remove(pOutStream); OnFeedData -= pOutStream.FeedData; OnSendStreamMessage -= pOutStream.SendStreamMessage; SignalOutStreamDetached(pOutStream); return(true); }
public override void Dispose() { base.Dispose(); foreach (var outStream in OutStreams) { OnFeedData -= outStream.FeedData; OnSendStreamMessage -= outStream.SendStreamMessage; outStream.UnLink(); } OutStreams.Clear(); }
protected override bool FeedMetaData(MediaFile pFile, MediaFrame mediaFrame) { //1. Seek into the data file at the correct position if (!pFile.SeekTo(mediaFrame.Start)) { FATAL("Unable to seek to position {0}", mediaFrame.Start); return(false); } var endPosition = pFile.Position + (long)mediaFrame.Length; //2. Read the data //_metadataBuffer.IgnoreAll(); //if (!_metadataBuffer.ReadFromFs(pFile, (int) mediaFrame.Length)) { // Logger.FATAL("Unable to read {0} bytes from offset {1}", mediaFrame.Length, mediaFrame.Start); // return false; //} //3. Parse the metadata _metadataName = ""; _metadataParameters.SetValue(); var _tempVariant = _amf0Reader.ReadVariant(); //if (!_amfSerializer.Read(_metadataBuffer, _tempVariant)) { // Logger.WARN("Unable to read metadata"); // return true; //} if (_tempVariant != VariantType.String) { WARN("Unable to read metadata"); return(true); } _metadataName = _tempVariant; while (pFile.Position < endPosition) { _metadataParameters.Add(_amf0Reader.ReadVariant()); } var message = GenericMessageFactory.GetNotify( ((BaseOutNetRTMPStream )OutStreams.Last()).CommandsChannelId, ((BaseOutNetRTMPStream )OutStreams.Last()).RTMPStreamId, mediaFrame.AbsoluteTime, true, _metadataName, _metadataParameters); //5. Send it return(((BaseRTMPProtocol )Protocol).SendMessage(message, true)); }
public override bool Stop() { if (PublisherId == 0) { return(true); } foreach (var baseOutStream in OutStreams.OfType <IOutNetStream>()) { baseOutStream.SendUnpublishNotify(); } _controller.WriteStatusResponse("Unpublish.Success", Name + " is now unpublished"); Flush(); PublisherId = 0; _publisher = null; return(true); }
public override void ReadyForSend() { lock (this) { if (!Feed()) { Logger.FATAL("Feed failed"); if (OutStreams.Any()) { OutStreams.Last().EnqueueForDelete(); } } else { Flush(); } } }
protected override bool FeedOtherType() { if (_currentFrame.Type == MediaFrameType.Message && OutStreams.Last() is BaseOutNetRTMPStream) { if (!_pFile.SeekTo(_currentFrame.Start)) { FATAL("Unable to seek to position {0}", _currentFrame.Start); return(false); } var buffer = new BufferWithOffset(_amf0Reader.BaseStream, false, (int)_currentFrame.Length); SendStreamMessage(buffer); _pFile.Position = _currentFrame.Start + _currentFrame.Length; //message.Recycle(); _currentFrameIndex++; return(true); } //todo 这里会导致播放中断,对于其他协议要修改 Paused = true; return(base.FeedOtherType()); }
public override bool FeedData(Stream pData, uint dataLength, uint processedLength, uint totalLength, uint absoluteTimestamp, bool isAudio) { switch (_rtcpPresence) { case RtcpPresence.Unknown: if (_rtcpDetectionInterval == TimeSpan.Zero) { WARN("RTCP disabled on stream {0}({1}) with name {2}. A/V drifting may occur over long periods of time", Type.TagToString(), UniqueId, Name); _rtcpPresence = RtcpPresence.Absent; return(true); } if (_rtcpDetectionStart == DateTime.MinValue) { _rtcpDetectionStart = DateTime.Now; return(true); } if (DateTime.Now - _rtcpDetectionStart > _rtcpDetectionInterval) { WARN("Stream {0}({1}) with name {2} doesn't have RTCP. A/V drifting may occur over long periods of time", Type.TagToString(), UniqueId, Name); _rtcpPresence = RtcpPresence.Absent; return(true); } var audioRTCPPresent = !_hasAudio || _audioNTP != 0; var videoRTCPPresent = !_hasVideo || _videoNTP != 0; if (audioRTCPPresent && videoRTCPPresent) { _rtcpPresence = RtcpPresence.Available; } return(true); case RtcpPresence.Available: var rtp = isAudio ? _audioRTP : _videoRTP; var ntp = isAudio ? _audioNTP : _videoNTP; absoluteTimestamp = (uint)(ntp + absoluteTimestamp - rtp); break; case RtcpPresence.Absent: var firstTimestamp = isAudio ? _audioFirstTimestamp : _videoFirstTimestamp; if (firstTimestamp < 0) { firstTimestamp = absoluteTimestamp; } absoluteTimestamp -= (uint)firstTimestamp; break; default: return(false); } var lastTs = isAudio ? _audioLastTs : _videoLastTs; if (-1.0 < lastTs * 100.0 - absoluteTimestamp * 100.0 && lastTs * 100.0 - absoluteTimestamp * 100.0 < 1.0) { absoluteTimestamp = lastTs; } if (lastTs > absoluteTimestamp) { WARN("Back time on {0} ATS:{1} LTS:{2} D:{3}", Name, absoluteTimestamp, lastTs, lastTs - absoluteTimestamp); return(true); } if (isAudio) { _audioLastTs = absoluteTimestamp; } else { _videoLastTs = absoluteTimestamp; } if (!_avCodecsSent) { foreach (var temp in OutStreams.Where(x => !x.IsEnqueueForDelete())) { SignalOutStreamAttached(temp); } if (!_avCodecsSent) { return(true); } } if (_hasAudio && _hasVideo && ((_audioLastTs == 0) || (_videoLastTs == 0))) { return(true); } return(base.FeedData(pData, dataLength, processedLength, totalLength, absoluteTimestamp, isAudio)); }
public override void GetStats(Variant info, uint namespaceId) { base.GetStats(info, namespaceId); info["outStreamsUniqueIds"] = Variant.Get(OutStreams.Select(x => Variant.Get((((ulong)namespaceId) << 32) | x.UniqueId)).ToList()); info.Add("bandwidth", Capabilities?.BandwidthHint ?? 0); }
protected virtual bool Feed() { //2. First, send audio and video codecs if (!_audioVideoCodecsSent && !SendCodecs()) { Logger.FATAL("Unable to send audio codec"); return(false); } while (!Paused && OutStreams.Count != 0) { //2. Determine if the client has enough data on the buffer and continue //or stay put var elapsedTime = (int)(DateTime.Now - _startFeedingTime).TotalSeconds; if ((int)_totalSentTime - elapsedTime >= _clientSideBufferLength) { return(true); } //3. Test to see if we have sent the last frame if (_currentFrameIndex >= _totalFrames || _playLimit >= 0 && _playLimit < _totalSentTime) { this.Log().Info("Done streaming file"); OutStreams.Last().SignalStreamCompleted(); Paused = true; return(true); } //4. Read the current frame from the seeking file if (!_pSeekFile.SeekTo(_framesBaseOffset + _currentFrameIndex * MediaFrame.MediaFrameSize)) { Logger.FATAL("Unablt to seek inside seek file"); return(false); } if (!MediaFrame.ReadFromMediaFile(_pSeekFile, out _currentFrame)) { Logger.FATAL("Unable to read frame from seeking file"); return(false); } Stream buffer = null; //Debug.WriteLine("{2},{0}:{1}", _currentFrame.AbsoluteTime, _currentFrame.Type, _currentFrameIndex); switch (_currentFrame.Type) { case MediaFrameType.Data: _currentFrameIndex++; if (!FeedMetaData(_pFile, _currentFrame)) { Logger.FATAL("Unable to feed metadata"); return(false); } break; case MediaFrameType.Audio: buffer = _audioBuffer; goto case MediaFrameType.Video; case MediaFrameType.Video: if (buffer == null) { buffer = _videoBuffer; } //7. Build the frame if (!BuildFrame(_pFile, _currentFrame, buffer)) { Logger.FATAL("Unable to build the frame"); return(false); } //8. Compute the timestamp _totalSentTime = _currentFrame.AbsoluteTime / 1000 - _totalSentTimeBase; //9. Do the feedeng FeedData(buffer, (uint)buffer.Length, 0, (uint)buffer.Length, _currentFrame.AbsoluteTime, _currentFrame.Type == MediaFrameType.Audio); //10. Discard the data buffer.IgnoreAll(); //11. Increment the frame index _currentFrameIndex++; //12. Done. We either feed again if frame length was 0 //or just return true //return _currentFrame.Length != 0 || Feed(); break; default: if (!FeedOtherType()) { return(false); } break; } } return(true); }