//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;
        }
        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;
        }
 /*
  * CanInterrupt will be true for regular messages triggered by the app's normal event logic. When a message
  * is played from the 'immediate' queue this will be false (spotter calls, command responses, some edge cases
  * where the message is time-critical). If this flag is true the presence of a message in the immediate queue
  * will make the app skip this sound if immediate_messages_block_other_messages is enabled.
  */
 private static Boolean CanInterrupt(SoundMetadata metadata)
 {
     // is this sufficient? Should the spotter be able to interrupt voice comm responses?
     return(metadata.type == SoundType.REGULAR_MESSAGE);
 }