Esempio n. 1
0
        /// <summary>
        /// Performs various sanity checks on the given request object and repairs it as well as possible.
        /// Returns null on any error that cannot be recovered from.
        /// Examples:<list type="bullet">
        /// <item>
        /// No item <see cref="SoundPlaybackRequest.Sounds"/> may be null => returns null
        /// </item>
        /// <item>
        /// <see cref="SoundPlayback.Options"/> is null => Set to <see cref="PlaybackOptions.Default"/> instead
        /// </item>
        /// </list>
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        protected SoundPlaybackRequest SanityCheck(SoundPlaybackRequest request)
        {
            if (request == null)
            {
                return(null);
            }
            if (request.Sounds == null || request.Sounds.Count == 0)
            {
                return(null);
            }
            for (int i = 0; i < request.Sounds.Count; ++i)
            {
                var soundPlayback = request.Sounds[i];
                if (soundPlayback == null)
                {
                    return(null);
                }

                soundPlayback.Sound = GetCleanFile(soundPlayback.Sound);
                if (soundPlayback.Sound == null)
                {
                    return(null);
                }

                if (!soundPlayback.Options.SanityCheck())
                {
                    return(null);
                }
            }

            return(request);
        }
        public void Play(SoundboxContext context, SoundPlaybackRequest sounds)
        {
            if (sounds.Sounds.Count == 0)
            {
                PlaybackChanged?.Invoke(this, new ISoundChainPlaybackService.PlaybackEventArgs(
                                            soundsPlaying: new List <SoundPlayback>(),
                                            finished: true,
                                            fromStop: false,
                                            fromStopGlobal: false
                                            ));
                return;
            }

            Play(context, sounds, 0);
        }
Esempio n. 3
0
        /// <summary>
        /// Plays the given request's sound(s)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task Play(Users.User user, SoundPlaybackRequest request)
        {
            request = SanityCheck(request);
            if (request == null)
            {
                return;
            }

            var player = this.ServiceProvider.GetService(typeof(ISoundChainPlaybackService)) as ISoundChainPlaybackService;

            player.PlaybackChanged += (sender, args) =>
            {
                if (args.FromStopGlobal)
                {
                    return;
                }

                //update the sounds the player is currently playing
                lock (PlaybackLock)
                {
                    PlaybackContext playerContext;
                    if (!PlayersPlaying.TryGetValue(player, out playerContext))
                    {
                        //race condition, finished already?
                        return;
                    }

                    if (args.Finished)
                    {
                        PlayersPlaying.Remove(player);
                    }
                    else
                    {
                        playerContext.PlayingNow = args.SoundsPlaying;
                    }

                    FirePlaybackChanged();
                }
            };

            var context = new PlaybackContext(user, request, player);

            lock (PlaybackLock)
            {
                PlayersPlaying[player] = context;
                player.Play(this, request);
            }
        }
        /// <summary>
        /// Plays the sound at the given index and recursively calls <see cref="Play(SoundboxContext, SoundPlaybackRequest, int)"/> again
        /// to play the next sound as well as required.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sounds"></param>
        /// <param name="index"></param>
        protected void Play(SoundboxContext context, SoundPlaybackRequest sounds, int index)
        {
            if (Finished)
            {
                //aborted
                return;
            }

            var sound = sounds.Sounds[index];
            //whether to play the next sound when we're done here (i.e. this is not the last track of the chain)
            bool continueNextSound = index < (sounds.Sounds.Count - 1);
            //whether to use SoundService's callback to start the next sound (more accurate) or to use start a timer on our own to play the next sound in the chain
            bool continueInCallback = continueNextSound && (sound.Options.ChainDelayMs == 0 || !sound.Sound.MetaData.HasLength);

            var player = GetSoundService();

            player.PlaybackFinished += (sender, args) =>
            {
                if (args.FromStop)
                {
                    //nothing to do. handled in Stop() already
                    return;
                }

                bool finished = false;
                ICollection <SoundPlayback> soundsPlaying;

                lock (this)
                {
                    SoundsPlaying.Remove(sound);
                    PlayersPlaying.Remove(player);

                    if (++SoundsFinished == sounds.Sounds.Count)
                    {
                        //this was the last sound. we're all done now
                        finished = true;
                    }

                    if (!this.Finished)
                    {
                        this.Finished = finished;

                        if (!continueInCallback)
                        {
                            //don't fire the STOPPED event if we would send the START event right away anyway
                            soundsPlaying = new List <SoundPlayback>(this.SoundsPlaying);

                            //update our listeners
                            PlaybackChanged?.Invoke(this, new ISoundChainPlaybackService.PlaybackEventArgs(
                                                        soundsPlaying: soundsPlaying,
                                                        finished: finished,
                                                        fromStop: false,
                                                        fromStopGlobal: false
                                                        ));
                        }
                    }
                }

                if (continueInCallback)
                {
                    //TODO use a timer here for ChainDelayMs > 0
                    //next sound
                    Play(context, sounds, index + 1);
                }
            };
            lock (this)
            {
                //TODO async
                player.Play(context, sound);
                this.SoundsPlaying.Add(sound);
                this.PlayersPlaying.Add(player);

                //update our listeners
                ICollection <SoundPlayback> soundsPlaying = new List <SoundPlayback>(this.SoundsPlaying);

                PlaybackChanged?.Invoke(this, new ISoundChainPlaybackService.PlaybackEventArgs(
                                            soundsPlaying: soundsPlaying,
                                            finished: false,
                                            fromStop: false,
                                            fromStopGlobal: false
                                            ));
            }

            if (continueNextSound && !continueInCallback)
            {
                //start a timer to trigger the next sound.
                var timer = new System.Timers.Timer(Math.Max(0, sound.GetActualLength() + sound.Options.ChainDelayMs));
                timer.AutoReset = false;
                timer.Elapsed  += (tSender, tArgs) =>
                {
                    //cleanup
                    timer.Stop();
                    timer.Dispose();

                    //clip the current sound if required
                    if (sound.Options.ChainDelayMs < 0 && sound.Options.ChainDelayClip)
                    {
                        player.Stop();
                    }

                    //start the next sound
                    Play(context, sounds, index + 1);
                };
                timer.Start();
            }
        }
Esempio n. 5
0
 public PlaybackContext(User user, SoundPlaybackRequest request, ISoundChainPlaybackService player)
 {
     User    = user;
     Request = request;
     Player  = player;
 }
Esempio n. 6
0
 /// <summary>
 /// Plays a single or multiple sounds.
 /// </summary>
 /// <param name="request"></param>
 /// <returns></returns>
 public Task Play(SoundPlaybackRequest request)
 {
     return(GetSoundbox().Play(GetUser(), request));
 }