public static IPlaybillItem ToPlaybillItem(this PlaybillItemEntity entity) { MediaSourceEntity sourceEntity = entity.MediaSource; IMediaSource mediaSource = null; if (sourceEntity == null) { mediaSource = new NullMediaSource(entity.MediaSourceTitle, TimeSpan.FromSeconds(entity.MediaSourceDuration.Value)); } else { mediaSource = entity.MediaSource.ToMediaSource(entity); // FromEntity(entity, entity.MediaSource); } IPlaySource playSource = Create(entity, mediaSource); IPlaybillItem result = null; switch (entity.ScheduleMode) { case PlayScheduleMode.Auto: result = PlaybillItem.Auto(playSource); break; case PlayScheduleMode.Timing: result = PlaybillItem.Timing(playSource, entity.StartTime.Value); break; case PlayScheduleMode.TimingBreak: result = PlaybillItem.TimingBreak(playSource, entity.StartTime.Value); break; } result.Id = entity.Id; return(result); }
internal static AutoPlaybillItem CreateAutoPadding(TimeSpan duration) { IPlaySource playSource = FCSPlayout.Domain.PlaySource.CreateAutoPadding(duration); return(new AutoPlaybillItem(playSource) { IsAutoPadding = true }); }
public IPlaySource Merge(IPlaySource playSource) { if (!CanMerge(playSource)) { throw new InvalidOperationException(); } var range = FCSPlayout.Domain.PlayRange.Merge(this.PlayRange, playSource.PlayRange); return(this.Clone(range)); }
internal static PlayRange Adjust(this IPlaySource playSource, PlayRange playRange) { var range = playSource.MediaSource.Adjust(playRange); if (!playSource.PlayRange.Include(range)) { throw new ArgumentOutOfRangeException("playRange", string.Format("<{0}>无效,有效范围为{1}。", playRange, playSource.PlayRange)); } return(range); }
internal NormalPlaySource(IPlaySource playSource) { if (playSource == null) { throw new ArgumentNullException("playSource"); } var playRange = playSource.Adjust(playSource.PlayRange); this.MediaSource = playSource.MediaSource; this.PlayRange = playRange; }
public bool CanMerge(IPlaySource playSource) { if (!this.MediaSource.Equals(playSource.MediaSource)) { return(false); } if (!Equals(this.CGItems, playSource.CGItems)) { return(false); } return(FCSPlayout.Domain.PlayRange.CanMerge(this.PlayRange, playSource.PlayRange)); }
private async Task <IWaveSource> GetSoundSource(IPlaySource track, long position) { _soundSourceLoadingToken?.Cancel(); _soundSourceLoadingToken = new CancellationTokenSource(); var token = _soundSourceLoadingToken.Token; IWaveSource result = null; TrackBitrate = track.Bitrate; try { switch (track.Type) { case PlaySourceType.LocalFile: result = await Task.Run(() => CodecFactory.Instance.GetCodec(((LocalFilePlaySource)track).Path), token); break; case PlaySourceType.Http: result = await Task.Run(() => CodecFactory.Instance.GetCodec(((HttpPlaySource)track).WebUri), token); break; case PlaySourceType.Stream: result = new DmoMp3Decoder(((StreamPlaySource)track).Stream); break; default: throw new ArgumentOutOfRangeException(); } // ReSharper disable once AccessToDisposedClosure await Task.Run(() => result.Position = position, token); } catch (TaskCanceledException) { result?.Dispose(); return(null); } return(token.IsCancellationRequested ? null : result); }
public static PlaybillItem Timing(IPlaySource playSource, DateTime startTime) { return(new TimingPlaybillItem(playSource, startTime, false)); }
protected PlaybillItem(IPlaySource playSource, PlayScheduleMode scheduleMode) { this.Id = Guid.NewGuid(); this.PlaySource = playSource; this.ScheduleMode = scheduleMode; }
public static PlaybillItem TimingBreak(IPlaySource playSource, DateTime startTime) { return(new TimingPlaybillItem(playSource, startTime, true)); }
internal static AutoPlaybillItem Create(IPlaySource playSource) { return(CreateInternal(new NormalPlaySource(playSource))); }
public AutoPlaybillItem(IPlaySource playSource) : base(playSource, PlayScheduleMode.Auto) { }
internal static TimingPlaybillItem Create(DateTime startTime, IPlaySource playSource, bool isBreak) { return(new TimingPlaybillItem(startTime, new NormalPlaySource(playSource), isBreak)); }
public async Task <bool> OpenTrack(IPlaySource track, bool openCrossfading, long position) { IsLoading = true; if (!openCrossfading) { StopPlayback(); } if (_crossfadeService.IsFading) { _crossfadeService.Cancel(); } if (_soundSource != null && !openCrossfading) { _soundSource.Dispose(); } if (openCrossfading && _soundSource != null) { _soundOut.Stopped -= SoundOut_Stopped; _loopStream.StreamFinished -= LoopStream_StreamFinished; _simpleNotificationSource.BlockRead -= SimpleNotificationSource_BlockRead; _crossfadeService.CrossfadeOut(_soundOut, CrossfadeDuration).Forget(); _soundOut = null; } var tempSource = await GetSoundSource(track, position); if (tempSource == null) { return(false); } _soundSource = tempSource; if (_soundSource.WaveFormat.SampleRate < 44100) //Correct sample rate { _soundSource = _soundSource.ChangeSampleRate(44100); } _soundSource = _soundSource .AppendSource(x => new LoopStream(x), out _loopStream) .AppendSource(x => Equalizer.Create10BandEqualizer(x.ToSampleSource()), out _equalizer) .AppendSource(x => new SimpleNotificationSource(x) { Interval = 100 }, out _simpleNotificationSource) .ToWaveSource(); _loopStream.EnableLoop = IsLooping; _loopStream.StreamFinished += LoopStream_StreamFinished; _simpleNotificationSource.BlockRead += SimpleNotificationSource_BlockRead; for (var i = 0; i < EqualizerBands.Count; i++) { SetEqualizerBandValue(EqualizerBands.Bands[i].Value, i); } if (_soundOut == null) { _soundOut = _soundOutProvider.GetSoundOut(); _soundOut.Stopped += SoundOut_Stopped; } _soundOut.Initialize(_soundSource); _soundOut.Volume = Volume; IsLoading = false; OnTrackLengthChanged(); _playTimeStopwatch.Reset(); if (openCrossfading) { await TogglePlayPause(); _fadingService.FadeIn(_soundOut, Volume).Forget(); } CurrentStateChanged(); OnPositionChanged(); return(true); }
internal static PlaybillItem CreateAuto(IPlaySource playSource) { return(AutoPlaybillItem.Create(playSource)); }
internal static bool IsAutoPadding(this IPlaySource playSource) { return(playSource.MediaSource.IsAutoPadding()); }
private void AddTiming2(DateTime startTime, IPlaySource playSource) { // 验证操作的合法性。 ValidatePlayDuration(playSource.PlayRange.Duration); ValidateStartTime(startTime, false); EnsureNoTimingConflict(startTime, playSource.PlayRange.Duration); // 触发事件前置事件。 List <PlaybillItem> tempList = new List <PlaybillItem>(); // 重新计算调度信息。 DateTime beginTime; var prevIndex = _playlist.FindLastIndex(i => !i.IsSkipped() && i.ScheduleInfo.StopTime <= startTime); if (prevIndex == -1) { if (_playlist.Count == 0) { if (_playlist.HasMinStartTime() && _playlist.MinStartTime.Value < startTime) { beginTime = _playlist.MinStartTime.Value; } else { beginTime = startTime; } } else { beginTime = _playlist[0].ScheduleInfo.StartTime; // startTime; beginTime = beginTime > startTime ? startTime : beginTime; } // [prevIndex+1, index-1], 注:index-prevIndex+1 // 替换范围:[prevIndex+1, index-1] (删除的起始索引0==prevIndex+1,数量index==index-prevIndex-1) } else { beginTime = _playlist[prevIndex].ScheduleInfo.StopTime; // 注:prevIndex可能等于index-1。 // 当prevIndex小于index-1时。 // 替换范围:[prevIndex + 1, index-1] (删除的起始索引prevIndex + 1,数量index-prevIndex-1 ) // 当prevIndex等于index-1时。(删除的起始索引prevIndex + 1==index,数量index-prevIndex-1==0 ) // 在index处插入0个或1个。 } DateTime endTime; var nextIndex = _playlist.FindFirstIndex(prevIndex + 1, i => !i.IsSkipped() && i.ScheduleInfo.ScheduleMode == ScheduleMode.Timing && i.ScheduleInfo.StartTime > startTime); //beginTime = playItem.ScheduleInfo.StopTime; if (nextIndex == -1) { endTime = DateTime.MaxValue; nextIndex = _playlist.Count; // [index + 1, _playlist.Count - 1], 注:index + 1可能等于_playlist.Count - 1 // 替换范围:[index + 1, _playlist.Count - 1] (删除的起始索引index + 1, 数量nextIndex-index-1==_playlist.Count-index-1) } else { endTime = _playlist[nextIndex].ScheduleInfo.StartTime; // 注:nextIndex可能等于index+1。 // 当nextIndex大于index+1时。 // 替换范围:[index+1, nextIndex-1] (删除的起始索引index+1,数量nextIndex-index-1 ) // 当nextIndex等于index+1时。(删除的起始索引index+1, 数量nextIndex-index-1==0 ) // 在index+1处插入0个或1个。 } PlaybillItem playItem = PlaybillItem.CreateTiming(startTime, new NormalPlaySource(playSource), false); Debug.Assert(beginTime <= endTime); Debug.Assert(beginTime <= startTime && endTime > playItem.ScheduleInfo.StopTime); for (int i = prevIndex + 1; i < nextIndex; i++) { tempList.Add(_playlist[i].PlaybillItem); //builder.Add(_playlist[i].PlaybillItem); } // case 1: prevIndex + 1==nextIndex-1,替换起始位置prevIndex + 1,删除数量1 (nextIndex-1-prevIndex) // case 2: prevIndex + 1<nextIndex-1,替换起始位置prevIndex + 1,删除数量1 (nextIndex-1-prevIndex) // case 3: prevIndex + 1>nextIndex-1 // 替换范围为[prevIndex + 1, nextIndex-1] // 触发事件(表示操作完成)。 }
private void AddTiming(DateTime startTime, IPlaySource playSource) { // 验证操作的合法性。 ValidatePlayDuration(playSource.PlayRange.Duration); ValidateStartTime(startTime, false); EnsureNoTimingConflict(startTime, playSource.PlayRange.Duration); // 获取插入位置。 // 第一个开始时间大于等于startTime的索引(-1表示列表为空或开始时间全部小于startTime) int index = FindTimingInsertIndex(startTime); //_playlist.FindFirstIndex((i)=>!i.IsSkipped() && i.ScheduleInfo.StartTime>=startTime); //index = index < 0 ? _playlist.Count : index; // 下面的处理代码确保顺播片断不会被定时播分隔。 var tempIndex = index; while (tempIndex < _playlist.Count) { var item = _playlist[tempIndex]; if (item.ScheduleInfo.ScheduleMode == ScheduleMode.Timing) { break; } else if (item.ScheduleInfo.ScheduleMode == ScheduleMode.TimingBreak) { continue; } else if (!item.IsSegment() || item.IsFirstSegment()) { break; } else { if (tempIndex != index) { var temp = _playlist[tempIndex]; _playlist.RemoveAt(tempIndex); _playlist.Insert(index, temp); } index++; } tempIndex++; } // 触发事件前置事件。 PlaybillItem playItem = PlaybillItem.CreateTiming(startTime, new NormalPlaySource(playSource), false); Insert(index, playItem); // 重新计算调度信息。 DateTime beginTime; DateTime endTime; if (index == 0) { if (_playlist.HasMinStartTime() && _playlist.MinStartTime.Value < startTime) { beginTime = _playlist.MinStartTime.Value; endTime = startTime; using (var builder = Build()) { Replace(0, 0, builder.Build(beginTime, endTime)); } } } else if (index > 0) // 有前部片断 { var prevIndex = _playlist.FindLastIndex(index - 1, i => !i.IsSkipped() && i.ScheduleInfo.StopTime <= startTime); endTime = startTime; if (prevIndex == -1) { beginTime = _playlist[0].ScheduleInfo.StartTime; // startTime; beginTime = beginTime > endTime ? endTime : beginTime; // [prevIndex+1, index-1], 注:index-prevIndex+1 // 替换范围:[prevIndex+1, index-1] (删除的起始索引0==prevIndex+1,数量index==index-prevIndex-1) } else { beginTime = _playlist[prevIndex].ScheduleInfo.StopTime; // 注:prevIndex可能等于index-1。 // 当prevIndex小于index-1时。 // 替换范围:[prevIndex + 1, index-1] (删除的起始索引prevIndex + 1,数量index-prevIndex-1 ) // 当prevIndex等于index-1时。(删除的起始索引prevIndex + 1==index,数量index-prevIndex-1==0 ) // 在index处插入0个或1个。 } using (var builder = Build()) { for (int i = prevIndex + 1; i < index; i++) { builder.Add(_playlist[i].PlaybillItem); } Replace(prevIndex + 1, index - prevIndex - 1, builder.Build(beginTime, endTime)); } } if (index < _playlist.Count - 1) // 有后部片断 { var nextIndex = _playlist.FindFirstIndex(index + 1, i => !i.IsSkipped() && i.ScheduleInfo.ScheduleMode == ScheduleMode.Timing); beginTime = playItem.ScheduleInfo.StopTime; if (nextIndex == -1) { endTime = DateTime.MaxValue; nextIndex = _playlist.Count; // [index + 1, _playlist.Count - 1], 注:index + 1可能等于_playlist.Count - 1 // 替换范围:[index + 1, _playlist.Count - 1] (删除的起始索引index + 1, 数量nextIndex-index-1==_playlist.Count-index-1) } else { endTime = _playlist[nextIndex].ScheduleInfo.StartTime; // 注:nextIndex可能等于index+1。 // 当nextIndex大于index+1时。 // 替换范围:[index+1, nextIndex-1] (删除的起始索引index+1,数量nextIndex-index-1 ) // 当nextIndex等于index+1时。(删除的起始索引index+1, 数量nextIndex-index-1==0 ) // 在index+1处插入0个或1个。 } using (var builder = Build()) { for (int i = index + 1; i < nextIndex; i++) { builder.Add(_playlist[i].PlaybillItem); } Replace(index + 1, nextIndex - index - 1, builder.Build(beginTime, endTime)); } } // 触发事件(表示操作完成)。 }
public static PlaybillItem Auto(IPlaySource playSource) { return(new AutoPlaybillItem(playSource)); }
private async Task<IWaveSource> GetSoundSource(IPlaySource track, long position) { _soundSourceLoadingToken?.Cancel(); _soundSourceLoadingToken = new CancellationTokenSource(); var token = _soundSourceLoadingToken.Token; IWaveSource result = null; TrackBitrate = track.Bitrate; try { switch (track.Type) { case PlaySourceType.LocalFile: result = await Task.Run(() => CodecFactory.Instance.GetCodec(((LocalFilePlaySource) track).Path), token); break; case PlaySourceType.Http: result = await Task.Run(() => CodecFactory.Instance.GetCodec(((HttpPlaySource) track).WebUri), token); break; case PlaySourceType.Stream: result = new DmoMp3Decoder(((StreamPlaySource) track).Stream); break; default: throw new ArgumentOutOfRangeException(); } // ReSharper disable once AccessToDisposedClosure await Task.Run(() => result.Position = position, token); } catch (TaskCanceledException) { result?.Dispose(); return null; } return token.IsCancellationRequested ? null : result; }
internal static PlaybillItem CreateTiming(DateTime startTime, IPlaySource playSource, bool isBreak) { return(TimingPlaybillItem.Create(startTime, playSource, isBreak)); }
public TimingPlaybillItem(IPlaySource playSource, DateTime startTime, bool isBreak) : base(playSource, isBreak ? PlayScheduleMode.TimingBreak : PlayScheduleMode.Timing) { base.StartTime = startTime; }
public async Task<bool> OpenTrack(IPlaySource track, bool openCrossfading, long position) { IsLoading = true; if (!openCrossfading) StopPlayback(); if (_crossfadeService.IsFading) _crossfadeService.Cancel(); if (_soundSource != null && !openCrossfading) _soundSource.Dispose(); if (openCrossfading && _soundSource != null) { _soundOut.Stopped -= SoundOut_Stopped; _loopStream.StreamFinished -= LoopStream_StreamFinished; _simpleNotificationSource.BlockRead -= SimpleNotificationSource_BlockRead; _crossfadeService.CrossfadeOut(_soundOut, CrossfadeDuration).Forget(); _soundOut = null; } var tempSource = await GetSoundSource(track, position); if (tempSource == null) return false; _soundSource = tempSource; if (_soundSource.WaveFormat.SampleRate < 44100) //Correct sample rate _soundSource = _soundSource.ChangeSampleRate(44100); _soundSource = _soundSource .AppendSource(x => new LoopStream(x), out _loopStream) .AppendSource(x => Equalizer.Create10BandEqualizer(x.ToSampleSource()), out _equalizer) .AppendSource(x => new SimpleNotificationSource(x) {Interval = 100}, out _simpleNotificationSource) .ToWaveSource(); _loopStream.EnableLoop = IsLooping; _loopStream.StreamFinished += LoopStream_StreamFinished; _simpleNotificationSource.BlockRead += SimpleNotificationSource_BlockRead; for (var i = 0; i < EqualizerBands.Count; i++) SetEqualizerBandValue(EqualizerBands.Bands[i].Value, i); if (_soundOut == null) { _soundOut = _soundOutProvider.GetSoundOut(); _soundOut.Stopped += SoundOut_Stopped; } _soundOut.Initialize(_soundSource); _soundOut.Volume = Volume; IsLoading = false; OnTrackLengthChanged(); _playTimeStopwatch.Reset(); if (openCrossfading) { await TogglePlayPause(); _fadingService.FadeIn(_soundOut, Volume).Forget(); } CurrentStateChanged(); OnPositionChanged(); return true; }