private static string GetSuggestedStartBleep(string chiefBleepSoundName, string spotterBleepSoundName)
        {
            var resolvedSoundName = chiefBleepSoundName;

            // If there's nothing to do return default value.
            if (!PlaybackModerator.IsFakeBleepInjectionEnabled())
            {
                return(resolvedSoundName);
            }

            // We need to capture the fact that channel was opened as Spotter or Chief, so that
            // subsequent injection is aware of that.
            PlaybackModerator.lastSoundWasSpotter = false;

            if (PlaybackModerator.PrevFirstKeyWasSpotter())
            {
                // Spotter uses opposite bleeps.
                resolvedSoundName = spotterBleepSoundName;
                PlaybackModerator.lastSoundWasSpotter = true;

                PlaybackModerator.Trace("Opening radio channel as Spotter");
            }
            else
            {
                PlaybackModerator.Trace("Opening radio channel as Chief");
            }

            return(resolvedSoundName);
        }
        //public static void PostProcessSound()
        //{ }

        public static bool ShouldPlaySound(SingleSound singleSound, SoundMetadata soundMetadata)
        {
            if (PlaybackModerator.crewChief != null && !PlaybackModerator.crewChief.running)
            {
                PlaybackModerator.Trace(string.Format("Sound {0} rejected because main thread is shutting down", singleSound.fullPath));
                return(false);
            }

            int messageId = soundMetadata == null ? 0 : soundMetadata.messageId;

            if (PlaybackModerator.lastBlockedMessageId == messageId)
            {
                PlaybackModerator.Trace(string.Format("Sound {0} rejected because other members of the same message have been blocked", singleSound.fullPath));
                return(false);
            }

            if (PlaybackModerator.rejectMessagesWhenTalking &&
                soundMetadata.type != SoundType.VOICE_COMMAND_RESPONSE &&
                SpeechRecogniser.waitingForSpeech &&
                MainWindow.voiceOption != MainWindow.VoiceOptionEnum.ALWAYS_ON)
            {
                PlaybackModerator.Trace(string.Format("Sound {0} rejected because we're in the middle of a voice command", singleSound.fullPath));
                if (messageId != 0)
                {
                    PlaybackModerator.lastBlockedMessageId = messageId;
                }

                return(false);
            }

            if (PlaybackModerator.minPriorityForInterrupt != SoundType.OTHER && PlaybackModerator.CanInterrupt(soundMetadata))
            {
                SoundType mostImportantTypeInImmediateQueue = PlaybackModerator.audioPlayer.getPriortyOfFirstWaitingImmediateMessage();
                if (mostImportantTypeInImmediateQueue <= PlaybackModerator.minPriorityForInterrupt)
                {
                    PlaybackModerator.Trace(string.Format("Blocking queued messasge {0} because at least 1 {1} message is waiting",
                                                          singleSound.fullPath, mostImportantTypeInImmediateQueue));

                    PlaybackModerator.Trace("Messages triggering block logic: " + audioPlayer.getMessagesBlocking(minPriorityForInterrupt));

                    if (messageId != 0)
                    {
                        PlaybackModerator.lastBlockedMessageId = messageId;
                    }

                    // ensure the blocking message won't expire
                    var firstWaitingMessage = PlaybackModerator.audioPlayer.getFirstWaitingImmediateMessage(mostImportantTypeInImmediateQueue);
                    if (firstWaitingMessage != null && firstWaitingMessage.expiryTime > 0)
                    {
                        firstWaitingMessage.expiryTime = firstWaitingMessage.expiryTime + 2000;
                    }

                    return(false);
                }
            }
            return(true);
        }
        public static void PreProcessSound(SingleSound sound, SoundMetadata soundMetadata)
        {
            if (PlaybackModerator.audioPlayer == null)
            {
                return;
            }

            //PlaybackModerator.Trace($"Pre-Processing sound: {sound.fullPath}  isSpotter: {sound.isSpotter}  isBleep: {sound.isBleep} ");

            PlaybackModerator.InjectBeepOutIn(sound, soundMetadata);

            PlaybackModerator.lastSoundPreProcessed = sound;
        }
        public static bool MessageCanBeQueued(QueuedMessage queuedMessage, int currentQueueDepth, DateTime now)
        {
            int       priority;
            SoundType type;

            if (queuedMessage.metadata == null)
            {
                PlaybackModerator.Trace("Message " + queuedMessage.messageName + " has no metadata, setting priority and type to default");
                priority = SoundMetadata.DEFAULT_PRIORITY;
                type     = SoundType.REGULAR_MESSAGE;
            }
            else
            {
                priority = queuedMessage.metadata.priority;
                type     = queuedMessage.metadata.type;
            }

            var canPlay = priority >= PlaybackModerator.minPriorityForEachVerbosity[verbosity];

            if (canPlay)
            {
                // not using this Dictionary of played messages so no point in adding data to it. Will leave this code
                // here for now in case i come up with a use-case

                /*
                 * MessageQueueCounter counter;
                 * if (PlaybackModerator.queuedMessageCounters.TryGetValue(queuedMessage.messageName, out counter))
                 * {
                 *  counter.timeQueued = now;
                 *  counter.numberOfTimesQueued = counter.numberOfTimesQueued + 1;
                 * }
                 * else
                 * {
                 *  PlaybackModerator.queuedMessageCounters.Add(queuedMessage.messageName, new MessageQueueCounter(now));
                 * }
                 */
            }
            else
            {
                PlaybackModerator.Trace(string.Format("Message {0} hasn't been queued because its priority is {1} and our verbosity is currently {2}", queuedMessage.messageName, priority, verbosity));
            }

            return(canPlay);
        }
        public static string GetSuggestedBleepEnd()
        {
            var resolvedSoundName = "end_bleep";

            // If there's nothing to do return default value.
            if (!PlaybackModerator.IsFakeBleepInjectionEnabled())
            {
                return(resolvedSoundName);
            }

            if (PlaybackModerator.PrevLastKeyWasSpotter())
            {
                // Spotter uses opposite bleeps.
                resolvedSoundName = "alternate_end_bleep";

                PlaybackModerator.Trace("Closing radio channel as Spotter");

                if (PlaybackModerator.lastSoundPreProcessed != null &&
                    !PlaybackModerator.lastSoundPreProcessed.isSpotter)
                {
                    PlaybackModerator.Trace(string.Format(
                                                "WARNING Last key and last sound pre-processed do not agree on role: {0} vs {1} ",
                                                PlaybackModerator.lastSoundPreProcessed.fullPath, PlaybackModerator.prevLastKey));
                }
            }
            else
            {
                PlaybackModerator.Trace("Closing radio channel as Chief");

                if (PlaybackModerator.lastSoundPreProcessed != null &&
                    PlaybackModerator.lastSoundPreProcessed.isSpotter)
                {
                    PlaybackModerator.Trace(string.Format(
                                                "WARNING Last key and last sound pre-processed do not agree on role: {0} vs {1} ",
                                                PlaybackModerator.lastSoundPreProcessed.fullPath, PlaybackModerator.lastSoundPreProcessed.fullPath));
                }
            }

            return(resolvedSoundName);
        }
        private static void InjectBeepOutIn(SingleSound sound, SoundMetadata soundMetadata)
        {
            Debug.Assert(PlaybackModerator.audioPlayer != null, "audioPlayer is not set.");

            // Only consider injection is preference is set and Spotter and Chief are different personas.
            if (!PlaybackModerator.IsFakeBleepInjectionEnabled())
            {
                return;
            }

            // Skip bleep sounds.
            if (sound.isBleep)
            {
                return;
            }

            // Inject bleep out/in if needed.
            var isSpotterSound = sound.isSpotter;  // Alternatively, we could assign a role to each queued sound.  We'll need this if we get more "personas" than Chief and Spotter.

            if (((!PlaybackModerator.lastSoundWasSpotter && isSpotterSound) || // If we are flipping from the Chief to Spotter
                 (PlaybackModerator.lastSoundWasSpotter && !isSpotterSound)) && // Or from the Spotter to Chief
                PlaybackModerator.audioPlayer.isChannelOpen() &&  // And, channel is still open
                (PlaybackModerator.lastSoundPreProcessed == null || !PlaybackModerator.lastSoundPreProcessed.isBleep))      // and the last sound wasn't also a beep (to stop the spotter kicking off with a double-beep)
            {
                // Ok, so idea here is that Chief and Spotter have different bleeps.  So we use opposing sets.
                string keyBleepOut = null;
                string keyBleepIn  = null;

                string traceMsgPostfix = null;
                if (isSpotterSound)
                {
                    // Spotter uses opposite blips.
                    keyBleepOut = "end_bleep";  // Chief uses regular bleeps.
                    keyBleepIn  = "alternate_short_start_bleep";

                    traceMsgPostfix = "Spotter interrupted Chief.";
                }
                else  // Chief comes in.
                {
                    keyBleepOut = "alternate_end_bleep";  // Spotter uses alternate bleeps
                    keyBleepIn  = "short_start_bleep";

                    traceMsgPostfix = "Chief interrupted Spotter.";
                }

                PlaybackModerator.Trace(string.Format("Injecting: {0} and {1} messages. {2}", keyBleepOut, keyBleepIn, traceMsgPostfix));

                // insert bleep out/in
                if (PlaybackModerator.insertBeepOutBetweenSpotterAndChief)
                {
                    PlaybackModerator.audioPlayer.getSoundCache().Play(keyBleepOut, soundMetadata);
                }

                // would be nice to have some slight random silence here
                if (PlaybackModerator.insertBeepInBetweenSpotterAndChief)
                {
                    PlaybackModerator.audioPlayer.getSoundCache().Play(keyBleepIn, soundMetadata);
                }
            }

            PlaybackModerator.lastSoundWasSpotter = isSpotterSound;
        }
 public static string GetSuggestedBleepStart()
 {
     return(PlaybackModerator.GetSuggestedStartBleep("start_bleep" /*chiefBleepSoundName*/, "alternate_start_bleep" /*spotterBleepSoundName*/));
 }