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);
        }
Example #2
0
        internal static AutoPlaybillItem CreateAutoPadding(TimeSpan duration)
        {
            IPlaySource playSource = FCSPlayout.Domain.PlaySource.CreateAutoPadding(duration);

            return(new AutoPlaybillItem(playSource)
            {
                IsAutoPadding = true
            });
        }
Example #3
0
        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));
        }
Example #4
0
        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);
        }
Example #5
0
        internal NormalPlaySource(IPlaySource playSource)
        {
            if (playSource == null)
            {
                throw new ArgumentNullException("playSource");
            }

            var playRange = playSource.Adjust(playSource.PlayRange);

            this.MediaSource = playSource.MediaSource;
            this.PlayRange   = playRange;
        }
Example #6
0
        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);
        }
Example #8
0
 public static PlaybillItem Timing(IPlaySource playSource, DateTime startTime)
 {
     return(new TimingPlaybillItem(playSource, startTime, false));
 }
Example #9
0
 protected PlaybillItem(IPlaySource playSource, PlayScheduleMode scheduleMode)
 {
     this.Id           = Guid.NewGuid();
     this.PlaySource   = playSource;
     this.ScheduleMode = scheduleMode;
 }
Example #10
0
 public static PlaybillItem TimingBreak(IPlaySource playSource, DateTime startTime)
 {
     return(new TimingPlaybillItem(playSource, startTime, true));
 }
Example #11
0
 internal static AutoPlaybillItem Create(IPlaySource playSource)
 {
     return(CreateInternal(new NormalPlaySource(playSource)));
 }
Example #12
0
 public AutoPlaybillItem(IPlaySource playSource)
     : base(playSource, PlayScheduleMode.Auto)
 {
 }
Example #13
0
 internal static TimingPlaybillItem Create(DateTime startTime, IPlaySource playSource, bool isBreak)
 {
     return(new TimingPlaybillItem(startTime, new NormalPlaySource(playSource), isBreak));
 }
Example #14
0
        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);
        }
Example #15
0
 internal static PlaybillItem CreateAuto(IPlaySource playSource)
 {
     return(AutoPlaybillItem.Create(playSource));
 }
Example #16
0
 internal static bool IsAutoPadding(this IPlaySource playSource)
 {
     return(playSource.MediaSource.IsAutoPadding());
 }
Example #17
0
        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]
            // 触发事件(表示操作完成)。
        }
Example #18
0
        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));
                }
            }

            // 触发事件(表示操作完成)。
        }
Example #19
0
 public static PlaybillItem Auto(IPlaySource playSource)
 {
     return(new AutoPlaybillItem(playSource));
 }
Example #20
0
        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;
        }
Example #21
0
 internal static PlaybillItem CreateTiming(DateTime startTime, IPlaySource playSource, bool isBreak)
 {
     return(TimingPlaybillItem.Create(startTime, playSource, isBreak));
 }
Example #22
0
 public TimingPlaybillItem(IPlaySource playSource, DateTime startTime, bool isBreak)
     : base(playSource, isBreak ? PlayScheduleMode.TimingBreak : PlayScheduleMode.Timing)
 {
     base.StartTime = startTime;
 }
Example #23
0
        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;
        }