Example #1
0
        public override void OnInspectorGUI()
        {
            this.serializedObject.UpdateIfRequiredOrScript();
            //serializedObject.Update();
            WebRtcAudioDsp webRtcAudioDsp         = this.recorder.GetComponent <WebRtcAudioDsp>();
            bool           webRtcAudioDspAttached = webRtcAudioDsp && webRtcAudioDsp != null && webRtcAudioDsp.enabled;

            if (PhotonVoiceEditorUtils.IsInTheSceneInPlayMode(this.recorder.gameObject))
            {
                if (this.recorder.RequiresRestart)
                {
                    EditorGUILayout.HelpBox("Recorder requires restart. Call Recorder.RestartRecording().", MessageType.Warning);
                    if (GUILayout.Button("RestartRecording"))
                    {
                        this.recorder.RestartRecording();
                    }
                }
                else if (!this.recorder.IsInitialized)
                {
                    EditorGUILayout.HelpBox("Recorder requires initialization. Call Recorder.Init or VoiceConnection.InitRecorder.", MessageType.Warning);
                }
            }
            VoiceLogger.ExposeLogLevel(this.serializedObject, this.recorder);

            EditorGUI.BeginChangeCheck();
            if (PhotonVoiceEditorUtils.IsInTheSceneInPlayMode(this.recorder.gameObject))
            {
                #if !UNITY_ANDROID && !UNITY_IOS
                this.recorder.ReactOnSystemChanges = EditorGUILayout.Toggle(new GUIContent("React On System Changes", "If true, recording is restarted when Unity detects Audio Config. changes."), this.recorder.ReactOnSystemChanges);
                if (this.recorder.ReactOnSystemChanges)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(this.skipDeviceChecksSp, new GUIContent("Skip Device Checks", "If true, restarts recording without checking if audio config/device changes affected recording."));
                    EditorGUI.indentLevel--;
                }
                #endif
                this.recorder.RecordOnlyWhenEnabled = EditorGUILayout.Toggle(new GUIContent("Record Only When Enabled", "If true, component will work only when enabled and active in hierarchy."),
                                                                             this.recorder.RecordOnlyWhenEnabled);
                EditorGUILayout.PropertyField(this.stopRecordingWhenPausedSp,
                                              new GUIContent("Stop Recording When Paused",
                                                             "If true, stop recording when paused resume/restart when un-paused."));
                this.recorder.TransmitEnabled = EditorGUILayout.Toggle(new GUIContent("Transmit Enabled", "If true, audio transmission is enabled."), this.recorder.TransmitEnabled);
                if (this.recorder.IsInitialized)
                {
                    this.recorder.IsRecording = EditorGUILayout.Toggle(new GUIContent("IsRecording", "If true, audio recording is on."), this.recorder.IsRecording);
                }
                else
                {
                    EditorGUILayout.PropertyField(this.autoStartSp,
                                                  new GUIContent("Auto Start", "If true, recording is started when Recorder is initialized."));
                }
                if (this.recorder.IsRecording && this.recorder.TransmitEnabled)
                {
                    float amplitude = 0f;
                    if (this.recorder.IsCurrentlyTransmitting)
                    {
                        amplitude = this.recorder.LevelMeter.CurrentPeakAmp;
                    }
                    EditorGUILayout.Slider("Level", amplitude, 0, 1);
                }
                this.recorder.Encrypt       = EditorGUILayout.Toggle(new GUIContent("Encrypt", "If true, voice stream is sent encrypted."), this.recorder.Encrypt);
                this.recorder.InterestGroup = (byte)EditorGUILayout.IntField(new GUIContent("Interest Group", "Target interest group that will receive transmitted audio."), this.recorder.InterestGroup);
                if (this.recorder.InterestGroup == 0)
                {
                    this.recorder.DebugEchoMode = EditorGUILayout.Toggle(new GUIContent("Debug Echo", "If true, outgoing stream routed back to client via server same way as for remote client's streams."), this.recorder.DebugEchoMode);
                }
                this.recorder.ReliableMode = EditorGUILayout.Toggle(new GUIContent("Reliable Mode", "If true, stream data sent in reliable mode."), this.recorder.ReliableMode);

                EditorGUILayout.LabelField("Codec Parameters", EditorStyles.boldLabel);
                this.recorder.FrameDuration = (OpusCodec.FrameDuration)EditorGUILayout.EnumPopup(new GUIContent("Frame Duration", "Outgoing audio stream encoder delay."), this.recorder.FrameDuration);
                this.recorder.SamplingRate  = (POpusCodec.Enums.SamplingRate)EditorGUILayout.EnumPopup(
                    new GUIContent("Sampling Rate", "Outgoing audio stream sampling rate."), this.recorder.SamplingRate);
                this.recorder.Bitrate = EditorGUILayout.IntField(new GUIContent("Bitrate", "Outgoing audio stream bitrate."),
                                                                 this.recorder.Bitrate);

                EditorGUILayout.LabelField("Audio Source Settings", EditorStyles.boldLabel);
                this.recorder.SourceType = (Recorder.InputSourceType)EditorGUILayout.EnumPopup(new GUIContent("Input Source Type", "Input audio data source type"), this.recorder.SourceType);
                switch (this.recorder.SourceType)
                {
                case Recorder.InputSourceType.Microphone:
                    this.recorder.MicrophoneType = (Recorder.MicType)EditorGUILayout.EnumPopup(
                        new GUIContent("Microphone Type",
                                       "Which microphone API to use when the Source is set to UnityMicrophone."),
                        this.recorder.MicrophoneType);
                    this.recorder.UseMicrophoneTypeFallback = EditorGUILayout.Toggle(new GUIContent("Use Fallback", "If true, if recording fails to start with Unity microphone type, Photon microphone type is used -if available- as a fallback and vice versa."), this.recorder.UseMicrophoneTypeFallback);
                    EditorGUILayout.HelpBox("Devices list and current selection is valid in Unity Editor only. In build, you need to set it via code preferably at runtime.", MessageType.Info);
                    switch (this.recorder.MicrophoneType)
                    {
                    case Recorder.MicType.Unity:
                        if (UnityMicrophone.devices.Length == 0)
                        {
                            EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                        }
                        else
                        {
                            this.unityMicrophoneDeviceIndex     = EditorGUILayout.Popup("Microphone Device", this.GetUnityMicrophoneDeviceIndex(), UnityMicrophone.devices);
                            this.recorder.UnityMicrophoneDevice = UnityMicrophone.devices[this.unityMicrophoneDeviceIndex];
                            int minFreq, maxFreq;
                            UnityMicrophone.GetDeviceCaps(UnityMicrophone.devices[this.unityMicrophoneDeviceIndex], out minFreq, out maxFreq);
                            EditorGUILayout.LabelField("Microphone Device Caps", string.Format("{0}..{1} Hz", minFreq, maxFreq));
                        }
                        break;

                    case Recorder.MicType.Photon:
                                #if PHOTON_MICROPHONE_ENUMERATOR
                        if (Recorder.PhotonMicrophoneEnumerator.IsSupported)
                        {
                            if (Recorder.PhotonMicrophoneEnumerator.Count == 0)
                            {
                                EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                            }
                            else
                            {
                                EditorGUILayout.BeginHorizontal();
                                this.photonDeviceIndex = EditorGUILayout.Popup("Microphone Device", this.photonDeviceIndex, this.photonDeviceNames);
                                this.recorder.PhotonMicrophoneDeviceId = this.photonDeviceIDs[this.photonDeviceIndex];
                                if (GUILayout.Button("Refresh", EditorStyles.miniButton, GUILayout.Width(70)))
                                {
                                    this.RefreshPhotonMicrophoneDevices();
                                }
                                EditorGUILayout.EndHorizontal();
                            }
                        }
                        else
                        {
                            this.recorder.PhotonMicrophoneDeviceId = -1;
                            EditorGUILayout.HelpBox("PhotonMicrophoneEnumerator Not Supported", MessageType.Error);
                        }
                                #endif
                                #if UNITY_IOS
                        EditorGUILayout.LabelField("iOS Audio Session Parameters", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(this.useCustomAudioSessionParametersSp, new GUIContent("Use Custom"));
                        if (this.useCustomAudioSessionParametersSp.boolValue)
                        {
                            EditorGUILayout.PropertyField(this.audioSessionParametersCategorySp);
                            EditorGUILayout.PropertyField(this.audioSessionParametersModeSp);
                            EditorGUILayout.PropertyField(this.audioSessionParametersCategoryOptionsSp, true);
                        }
                        else
                        {
                            int index = EditorGUILayout.Popup("Preset", this.audioSessionPresetIndexSp.intValue, this.iOSAudioSessionPresetsNames);
                            if (index != this.audioSessionPresetIndexSp.intValue)
                            {
                                this.audioSessionPresetIndexSp.intValue = index;
                                AudioSessionParameters parameters = this.iOSAudioSessionPresetsValues[index];
                                this.SetEnumIndex(this.audioSessionParametersCategorySp,
                                                  typeof(AudioSessionCategory), parameters.Category);
                                this.SetEnumIndex(this.audioSessionParametersModeSp,
                                                  typeof(AudioSessionMode), parameters.Mode);
                                if (parameters.CategoryOptions != null)
                                {
                                    this.audioSessionParametersCategoryOptionsSp.ClearArray();
                                    this.audioSessionParametersCategoryOptionsSp.arraySize =
                                        parameters.CategoryOptions.Length;
                                    if (index == 0)
                                    {
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.DefaultToSpeaker);
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(1), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                    else if (index == 1)
                                    {
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                }
                            }
                        }
                        EditorGUI.indentLevel--;
                                #elif UNITY_ANDROID
                        EditorGUILayout.LabelField("Android Native Microphone Settings", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("AcousticEchoCancellation"));
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("AutomaticGainControl"));
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("NoiseSuppression"));
                        EditorGUI.indentLevel--;
                                #endif
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;

                case Recorder.InputSourceType.AudioClip:
                    this.recorder.AudioClip     = EditorGUILayout.ObjectField(new GUIContent("Audio Clip", "Source audio clip."), this.recorder.AudioClip, typeof(AudioClip), false) as AudioClip;
                    this.recorder.LoopAudioClip =
                        EditorGUILayout.Toggle(new GUIContent("Loop", "Loop playback for audio clip sources."),
                                               this.recorder.LoopAudioClip);
                    break;

                case Recorder.InputSourceType.Factory:
                    EditorGUILayout.HelpBox("Add a custom InputFactory method in code.", MessageType.Info);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                EditorGUILayout.LabelField("Voice Activity Detection (VAD)", EditorStyles.boldLabel);
                if (webRtcAudioDspAttached)
                {
                    if (webRtcAudioDsp.VAD)
                    {
                        EditorGUILayout.HelpBox("WebRtcAudioDsp.VAD is already enabled no need to use the built-in Recorder VAD", MessageType.Info);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("It's recommended to use VAD from WebRtcAudioDsp instead of built-in Recorder VAD", MessageType.Info);
                    }
                }
                this.recorder.VoiceDetection = EditorGUILayout.Toggle(new GUIContent("Detect", "If true, voice detection enabled."), this.recorder.VoiceDetection);
                if (this.recorder.VoiceDetection)
                {
                    if (webRtcAudioDspAttached && !webRtcAudioDsp.VAD && GUILayout.Button("Use WebRtcAudioDsp.VAD instead"))
                    {
                        this.recorder.VoiceDetection = false;
                        webRtcAudioDsp.VAD           = true;
                    }
                    this.recorder.VoiceDetectionThreshold =
                        EditorGUILayout.Slider(
                            new GUIContent("Threshold", "Voice detection threshold (0..1, where 1 is full amplitude)."),
                            this.recorder.VoiceDetectionThreshold, 0f, 1f);
                    this.recorder.VoiceDetectionDelayMs =
                        EditorGUILayout.IntField(new GUIContent("Delay (ms)", "Keep detected state during this time after signal level dropped below threshold. Default is 500ms"), this.recorder.VoiceDetectionDelayMs);
                    EditorGUILayout.HelpBox("Do not speak and stay in a silent environment when calibrating.", MessageType.Info);
                    if (this.recorder.VoiceDetectorCalibrating)
                    {
                        EditorGUILayout.LabelField(string.Format("Calibrating {0} ms", this.calibrationTime));
                    }
                    else
                    {
                        this.calibrationTime = EditorGUILayout.IntField("Calibration Time (ms)", this.calibrationTime);
                        if (this.recorder.IsRecording && this.recorder.TransmitEnabled)
                        {
                            if (GUILayout.Button("Calibrate"))
                            {
                                this.recorder.VoiceDetectorCalibrate(this.calibrationTime);
                            }
                        }
                    }
                }
            }
            else
            {
                #if !UNITY_ANDROID && !UNITY_IOS
                EditorGUILayout.PropertyField(this.reactOnSystemChangesSp,
                                              new GUIContent("React On System Changes",
                                                             "If true, recording is restarted when Unity detects Audio Config. changes."));
                if (this.reactOnSystemChangesSp.boolValue)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(this.skipDeviceChecksSp, new GUIContent("Skip Device Checks", "If true, restarts recording without checking if audio config/device changes affected recording."));
                    EditorGUI.indentLevel--;
                }
                #endif
                EditorGUILayout.PropertyField(this.recordOnlyWhenEnabledSp,
                                              new GUIContent("Record Only When Enabled",
                                                             "If true, component will work only when enabled and active in hierarchy."));
                EditorGUILayout.PropertyField(this.stopRecordingWhenPausedSp,
                                              new GUIContent("Stop Recording When Paused",
                                                             "If true, stop recording when paused resume/restart when un-paused."));
                EditorGUILayout.PropertyField(this.transmitEnabledSp,
                                              new GUIContent("Transmit Enabled", "If true, audio transmission is enabled."));
                EditorGUILayout.PropertyField(this.autoStartSp,
                                              new GUIContent("Auto Start", "If true, recording is started when Recorder is initialized."));
                EditorGUILayout.PropertyField(this.encryptSp,
                                              new GUIContent("Encrypt", "If true, voice stream is sent encrypted."));
                EditorGUILayout.PropertyField(this.interestGroupSp,
                                              new GUIContent("Interest Group", "Target interest group that will receive transmitted audio."));
                if (this.interestGroupSp.intValue == 0)
                {
                    EditorGUILayout.PropertyField(this.debugEchoModeSp,
                                                  new GUIContent("Debug Echo",
                                                                 "If true, outgoing stream routed back to client via server same way as for remote client's streams."));
                }
                else if (this.debugEchoModeSp.boolValue)
                {
                    Debug.LogWarningFormat("DebugEchoMode disabled because InterestGroup changed to {0}. DebugEchoMode works only with Interest Group 0.", this.interestGroupSp.intValue);
                    this.debugEchoModeSp.boolValue = false;
                }
                EditorGUILayout.PropertyField(this.reliableModeSp, new GUIContent("Reliable Mode",
                                                                                  "If true, stream data sent in reliable mode."));

                EditorGUILayout.LabelField("Codec Parameters", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(this.frameDurationSp,
                                              new GUIContent("Frame Duration", "Outgoing audio stream encoder delay."));
                EditorGUILayout.PropertyField(this.samplingRateSp,
                                              new GUIContent("Sampling Rate", "Outgoing audio stream sampling rate."));
                EditorGUILayout.PropertyField(this.bitrateSp,
                                              new GUIContent("Bitrate", "Outgoing audio stream bitrate."));

                EditorGUILayout.LabelField("Audio Source Settings", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(this.sourceTypeSp,
                                              new GUIContent("Input Source Type", "Input audio data source type"));
                switch ((Recorder.InputSourceType) this.sourceTypeSp.enumValueIndex)
                {
                case Recorder.InputSourceType.Microphone:
                    EditorGUILayout.PropertyField(this.microphoneTypeSp, new GUIContent("Microphone Type",
                                                                                        "Which microphone API to use when the Source is set to UnityMicrophone."));
                    EditorGUILayout.PropertyField(this.useMicrophoneTypeFallbackSp, new GUIContent("Use Fallback", "If true, if recording fails to start with Unity microphone type, Photon microphone type is used -if available- as a fallback and vice versa."));
                    EditorGUILayout.HelpBox("Devices list and current selection is valid in Unity Editor only. In build, you need to set it via code preferably at runtime.", MessageType.Info);
                    switch (this.recorder.MicrophoneType)
                    {
                    case Recorder.MicType.Unity:
                        if (UnityMicrophone.devices.Length == 0)
                        {
                            EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                        }
                        else
                        {
                            this.unityMicrophoneDeviceIndex          = EditorGUILayout.Popup("Microphone Device", this.GetUnityMicrophoneDeviceIndex(), UnityMicrophone.devices);
                            this.unityMicrophoneDeviceSp.stringValue = UnityMicrophone.devices[this.unityMicrophoneDeviceIndex];
                            int minFreq, maxFreq;
                            UnityMicrophone.GetDeviceCaps(UnityMicrophone.devices[this.unityMicrophoneDeviceIndex], out minFreq, out maxFreq);
                            EditorGUILayout.LabelField("Microphone Device Caps", string.Format("{0}..{1} Hz", minFreq, maxFreq));
                        }
                        break;

                    case Recorder.MicType.Photon:
                                #if PHOTON_MICROPHONE_ENUMERATOR
                        if (Recorder.PhotonMicrophoneEnumerator.IsSupported)
                        {
                            if (Recorder.PhotonMicrophoneEnumerator.Count == 0)
                            {
                                EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                            }
                            else
                            {
                                EditorGUILayout.BeginHorizontal();
                                this.photonDeviceIndex = EditorGUILayout.Popup("Microphone Device", this.photonDeviceIndex, this.photonDeviceNames);
                                this.photonMicrophoneDeviceIdSp.intValue = this.photonDeviceIDs[this.photonDeviceIndex];
                                if (GUILayout.Button("Refresh", EditorStyles.miniButton, GUILayout.Width(70)))
                                {
                                    this.RefreshPhotonMicrophoneDevices();
                                }
                                EditorGUILayout.EndHorizontal();
                            }
                        }
                        else
                        {
                            this.recorder.PhotonMicrophoneDeviceId = -1;
                            EditorGUILayout.HelpBox("PhotonMicrophoneEnumerator Not Supported", MessageType.Error);
                        }
                                #endif
                                #if UNITY_IOS
                        EditorGUILayout.LabelField("iOS Audio Session Parameters", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(this.useCustomAudioSessionParametersSp, new GUIContent("Use Custom"));
                        if (this.useCustomAudioSessionParametersSp.boolValue)
                        {
                            EditorGUILayout.PropertyField(this.audioSessionParametersCategorySp);
                            EditorGUILayout.PropertyField(this.audioSessionParametersModeSp);
                            EditorGUILayout.PropertyField(this.audioSessionParametersCategoryOptionsSp, true);
                        }
                        else
                        {
                            int index = EditorGUILayout.Popup("Preset", this.audioSessionPresetIndexSp.intValue, this.iOSAudioSessionPresetsNames);
                            if (index != this.audioSessionPresetIndexSp.intValue)
                            {
                                this.audioSessionPresetIndexSp.intValue = index;
                                AudioSessionParameters parameters = this.iOSAudioSessionPresetsValues[index];
                                this.SetEnumIndex(this.audioSessionParametersCategorySp,
                                                  typeof(AudioSessionCategory), parameters.Category);
                                this.SetEnumIndex(this.audioSessionParametersModeSp,
                                                  typeof(AudioSessionMode), parameters.Mode);
                                if (parameters.CategoryOptions != null)
                                {
                                    this.audioSessionParametersCategoryOptionsSp.ClearArray();
                                    this.audioSessionParametersCategoryOptionsSp.arraySize =
                                        parameters.CategoryOptions.Length;
                                    if (index == 0)
                                    {
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.DefaultToSpeaker);
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(1), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                    else if (index == 1)
                                    {
                                        this.SetEnumIndex(this.audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                }
                            }
                        }
                        EditorGUI.indentLevel--;
                                #elif UNITY_ANDROID
                        EditorGUILayout.LabelField("Android Native Microphone Settings", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("AcousticEchoCancellation"));
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("AutomaticGainControl"));
                        EditorGUILayout.PropertyField(this.nativeAndroidMicrophoneSettingsSp.FindPropertyRelative("NoiseSuppression"));
                        EditorGUI.indentLevel--;
                                #endif
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;

                case Recorder.InputSourceType.AudioClip:
                    EditorGUILayout.PropertyField(this.audioClipSp,
                                                  new GUIContent("Audio Clip", "Source audio clip."));
                    EditorGUILayout.PropertyField(this.loopAudioClipSp,
                                                  new GUIContent("Loop", "Loop playback for audio clip sources."));
                    break;

                case Recorder.InputSourceType.Factory:
                    EditorGUILayout.HelpBox("Add a custom InputFactory method in code.", MessageType.Info);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                EditorGUILayout.LabelField("Voice Activity Detection (VAD)", EditorStyles.boldLabel);
                if (webRtcAudioDspAttached)
                {
                    if (webRtcAudioDsp.VAD)
                    {
                        EditorGUILayout.HelpBox("WebRtcAudioDsp.VAD is already enabled no need to use the built-in Recorder VAD", MessageType.Info);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("It's recommended to use VAD from WebRtcAudioDsp instead of built-in Recorder VAD", MessageType.Info);
                    }
                }
                EditorGUILayout.PropertyField(this.voiceDetectionSp,
                                              new GUIContent("Detect", "If true, voice detection enabled."));
                if (this.voiceDetectionSp.boolValue)
                {
                    if (webRtcAudioDspAttached && !webRtcAudioDsp.VAD && GUILayout.Button("Use WebRtcAudioDsp.VAD instead"))
                    {
                        this.recorder.VoiceDetection = false;
                        webRtcAudioDsp.VAD           = true;
                    }
                    this.voiceDetectionThresholdSp.floatValue = EditorGUILayout.Slider(
                        new GUIContent("Threshold", "Voice detection threshold (0..1, where 1 is full amplitude)."),
                        this.voiceDetectionThresholdSp.floatValue, 0f, 1f);
                    this.voiceDetectionDelayMsSp.intValue =
                        EditorGUILayout.IntField(new GUIContent("Delay (ms)", "Keep detected state during this time after signal level dropped below threshold. Default is 500ms"), this.voiceDetectionDelayMsSp.intValue);
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                this.serializedObject.ApplyModifiedProperties();
            }
        }
        public override void OnInspectorGUI()
        {
            serializedObject.UpdateIfRequiredOrScript();
            //serializedObject.Update();

            if (PhotonVoiceEditorUtils.IsInTheSceneInPlayMode(recorder.gameObject))
            {
                if (recorder.RequiresRestart)
                {
                    EditorGUILayout.HelpBox("Recorder requires restart. Call Recorder.RestartRecording().", MessageType.Warning);
                    if (GUILayout.Button("RestartRecording"))
                    {
                        recorder.RestartRecording();
                    }
                }
                else if (!recorder.IsInitialized)
                {
                    EditorGUILayout.HelpBox("Recorder requires initialization. Call Recorder.Init or VoiceConnection.InitRecorder.", MessageType.Warning);
                }
            }
            VoiceLogger.ExposeLogLevel(serializedObject, recorder);

            EditorGUI.BeginChangeCheck();
            if (Application.isPlaying)
            {
                recorder.ReactOnSystemChanges = EditorGUILayout.Toggle(new GUIContent("React On System Changes", "If true, recording is restarted when Unity detects Audio Config. changes."), recorder.ReactOnSystemChanges);
                recorder.TransmitEnabled      = EditorGUILayout.Toggle(new GUIContent("Transmit Enabled", "If true, audio transmission is enabled."), recorder.TransmitEnabled);
                if (recorder.IsInitialized)
                {
                    recorder.IsRecording = EditorGUILayout.Toggle(new GUIContent("IsRecording", "If true, audio recording is on."), recorder.IsRecording);
                }
                else
                {
                    EditorGUILayout.PropertyField(this.autoStartSp,
                                                  new GUIContent("Auto Start", "If true, recording is started when Recorder is initialized."));
                }
                if (recorder.IsRecording && recorder.TransmitEnabled)
                {
                    float amplitude = 0f;
                    if (recorder.IsCurrentlyTransmitting)
                    {
                        amplitude = recorder.LevelMeter.CurrentPeakAmp;
                    }
                    EditorGUILayout.Slider("Level", amplitude, 0, 1);
                }
                recorder.Encrypt       = EditorGUILayout.Toggle(new GUIContent("Encrypt", "If true, voice stream is sent encrypted."), recorder.Encrypt);
                recorder.InterestGroup = (byte)EditorGUILayout.IntField(new GUIContent("Interest Group", "Target interest group that will receive transmitted audio."), recorder.InterestGroup);
                if (recorder.InterestGroup == 0)
                {
                    recorder.DebugEchoMode = EditorGUILayout.Toggle(new GUIContent("Debug Echo", "If true, outgoing stream routed back to client via server same way as for remote client's streams."), recorder.DebugEchoMode);
                }
                recorder.ReliableMode = EditorGUILayout.Toggle(new GUIContent("Reliable Mode", "If true, stream data sent in reliable mode."), recorder.ReliableMode);

                EditorGUILayout.LabelField("Codec Parameters", EditorStyles.boldLabel);
                recorder.FrameDuration = (OpusCodec.FrameDuration)EditorGUILayout.EnumPopup(new GUIContent("Frame Duration", "Outgoing audio stream encoder delay."), recorder.FrameDuration);
                recorder.SamplingRate  = (POpusCodec.Enums.SamplingRate)EditorGUILayout.EnumPopup(
                    new GUIContent("Sampling Rate", "Outgoing audio stream sampling rate."), recorder.SamplingRate);
                recorder.Bitrate = EditorGUILayout.IntField(new GUIContent("Bitrate", "Outgoing audio stream bitrate."),
                                                            recorder.Bitrate);

                EditorGUILayout.LabelField("Audio Source Settings", EditorStyles.boldLabel);
                recorder.SourceType = (Recorder.InputSourceType)EditorGUILayout.EnumPopup(new GUIContent("Input Source Type", "Input audio data source type"), recorder.SourceType);
                switch (recorder.SourceType)
                {
                case Recorder.InputSourceType.Microphone:
                    recorder.MicrophoneType = (Recorder.MicType)EditorGUILayout.EnumPopup(
                        new GUIContent("Microphone Type",
                                       "Which microphone API to use when the Source is set to Microphone."),
                        recorder.MicrophoneType);
                    EditorGUILayout.HelpBox("Devices list and current selection is valid in Unity Editor only. In build, you need to set it via code preferably at runtime.", MessageType.Info);
                    switch (recorder.MicrophoneType)
                    {
                    case Recorder.MicType.Unity:
                        if (Microphone.devices.Length == 0)
                        {
                            EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                        }
                        else
                        {
                            unityMicrophoneDeviceIndex     = EditorGUILayout.Popup("Microphone Device", unityMicrophoneDeviceIndex, Microphone.devices);
                            recorder.UnityMicrophoneDevice = Microphone.devices[unityMicrophoneDeviceIndex];
                            int minFreq, maxFreq;
                            Microphone.GetDeviceCaps(Microphone.devices[unityMicrophoneDeviceIndex], out minFreq, out maxFreq);
                            EditorGUILayout.LabelField("Microphone Device Caps", string.Format("{0}..{1} Hz", minFreq, maxFreq));
                        }
                        break;

                    case Recorder.MicType.Photon:
                                #if PHOTON_MICROPHONE_ENUMERATOR
                        if (Recorder.PhotonMicrophoneEnumerator.IsSupported)
                        {
                            if (Recorder.PhotonMicrophoneEnumerator.Count == 0)
                            {
                                EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                            }
                            else
                            {
                                EditorGUILayout.BeginHorizontal();
                                photonDeviceIndex = EditorGUILayout.Popup("Microphone Device", photonDeviceIndex, photonDeviceNames);
                                recorder.PhotonMicrophoneDeviceId = photonDeviceIDs[photonDeviceIndex];
                                if (GUILayout.Button("Refresh", EditorStyles.miniButton, GUILayout.Width(70)))
                                {
                                    this.RefreshPhotonMicrophoneDevices();
                                }
                                EditorGUILayout.EndHorizontal();
                            }
                        }
                        else
                        {
                            recorder.PhotonMicrophoneDeviceId = -1;
                            EditorGUILayout.HelpBox("PhotonMicrophoneEnumerator Not Supported", MessageType.Error);
                        }
                                #endif
                                #if UNITY_IOS
                        EditorGUILayout.LabelField("iOS Audio Session Parameters", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(useCustomAudioSessionParametersSp, new GUIContent("Use Custom"));
                        if (useCustomAudioSessionParametersSp.boolValue)
                        {
                            EditorGUILayout.PropertyField(audioSessionParametersCategorySp);
                            EditorGUILayout.PropertyField(audioSessionParametersModeSp);
                            EditorGUILayout.PropertyField(audioSessionParametersCategoryOptionsSp, true);
                        }
                        else
                        {
                            int index = EditorGUILayout.Popup("Preset", audioSessionPresetIndexSp.intValue, iOSAudioSessionPresetsNames);
                            if (index != audioSessionPresetIndexSp.intValue)
                            {
                                audioSessionPresetIndexSp.intValue = index;
                                AudioSessionParameters parameters = iOSAudioSessionPresetsValues[index];
                                this.SetEnumIndex(audioSessionParametersCategorySp,
                                                  typeof(AudioSessionCategory), parameters.Category);
                                this.SetEnumIndex(audioSessionParametersModeSp,
                                                  typeof(AudioSessionMode), parameters.Mode);
                                if (parameters.CategoryOptions != null)
                                {
                                    audioSessionParametersCategoryOptionsSp.ClearArray();
                                    audioSessionParametersCategoryOptionsSp.arraySize =
                                        parameters.CategoryOptions.Length;
                                    if (index == 0)
                                    {
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.DefaultToSpeaker);
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(1), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                    else if (index == 1)
                                    {
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                }
                            }
                        }
                        EditorGUI.indentLevel--;
                                #endif
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;

                case Recorder.InputSourceType.AudioClip:
                    recorder.AudioClip     = EditorGUILayout.ObjectField(new GUIContent("Audio Clip", "Source audio clip."), recorder.AudioClip, typeof(AudioClip), false) as AudioClip;
                    recorder.LoopAudioClip =
                        EditorGUILayout.Toggle(new GUIContent("Loop", "Loop playback for audio clip sources."),
                                               recorder.LoopAudioClip);
                    break;

                case Recorder.InputSourceType.Factory:
                    EditorGUILayout.HelpBox("Add a custom InputFactory method in code.", MessageType.Info);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                EditorGUILayout.LabelField("Voice Activity Detection (VAD)", EditorStyles.boldLabel);
                recorder.VoiceDetection = EditorGUILayout.Toggle(new GUIContent("Detect", "If true, voice detection enabled."), recorder.VoiceDetection);
                if (recorder.VoiceDetection)
                {
                    recorder.VoiceDetectionThreshold =
                        EditorGUILayout.Slider(
                            new GUIContent("Threshold", "Voice detection threshold (0..1, where 1 is full amplitude)."),
                            recorder.VoiceDetectionThreshold, 0f, 1f);
                    recorder.VoiceDetectionDelayMs =
                        EditorGUILayout.IntField(new GUIContent("Delay (ms)", "Keep detected state during this time after signal level dropped below threshold. Default is 500ms"), recorder.VoiceDetectionDelayMs);
                    EditorGUILayout.HelpBox("Do not speak and stay in a silent environment when calibrating.", MessageType.Info);
                    if (recorder.VoiceDetectorCalibrating)
                    {
                        EditorGUILayout.LabelField(string.Format("Calibrating {0} ms", calibrationTime));
                    }
                    else
                    {
                        calibrationTime = EditorGUILayout.IntField("Calibration Time (ms)", calibrationTime);
                        if (recorder.IsRecording && recorder.TransmitEnabled)
                        {
                            if (GUILayout.Button("Calibrate"))
                            {
                                recorder.VoiceDetectorCalibrate(calibrationTime);
                            }
                        }
                    }
                }
            }
            else
            {
                EditorGUILayout.PropertyField(this.reactOnSystemChangesSp,
                                              new GUIContent("React On System Changes",
                                                             "If true, recording is restarted when Unity detects Audio Config. changes."));
                EditorGUILayout.PropertyField(this.transmitEnabledSp,
                                              new GUIContent("Transmit Enabled", "If true, audio transmission is enabled."));
                EditorGUILayout.PropertyField(this.autoStartSp,
                                              new GUIContent("Auto Start", "If true, recording is started when Recorder is initialized."));
                EditorGUILayout.PropertyField(this.encryptSp,
                                              new GUIContent("Encrypt", "If true, voice stream is sent encrypted."));
                EditorGUILayout.PropertyField(this.interestGroupSp,
                                              new GUIContent("Interest Group", "Target interest group that will receive transmitted audio."));
                if (this.interestGroupSp.intValue == 0)
                {
                    EditorGUILayout.PropertyField(this.debugEchoModeSp,
                                                  new GUIContent("Debug Echo",
                                                                 "If true, outgoing stream routed back to client via server same way as for remote client's streams."));
                }
                else if (this.debugEchoModeSp.boolValue)
                {
                    Debug.LogWarningFormat("DebugEchoMode disabled because InterestGroup changed to {0}. DebugEchoMode works only with Interest Group 0.", this.interestGroupSp.intValue);
                    this.debugEchoModeSp.boolValue = false;
                }
                EditorGUILayout.PropertyField(this.reliableModeSp, new GUIContent("Reliable Mode",
                                                                                  "If true, stream data sent in reliable mode."));

                EditorGUILayout.LabelField("Codec Parameters", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(this.frameDurationSp,
                                              new GUIContent("Frame Duration", "Outgoing audio stream encoder delay."));
                EditorGUILayout.PropertyField(this.samplingRateSp,
                                              new GUIContent("Sampling Rate", "Outgoing audio stream sampling rate."));
                EditorGUILayout.PropertyField(this.bitrateSp,
                                              new GUIContent("Bitrate", "Outgoing audio stream bitrate."));

                EditorGUILayout.LabelField("Audio Source Settings", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(this.sourceTypeSp,
                                              new GUIContent("Input Source Type", "Input audio data source type"));
                switch ((Recorder.InputSourceType) this.sourceTypeSp.enumValueIndex)
                {
                case Recorder.InputSourceType.Microphone:
                    EditorGUILayout.PropertyField(this.microphoneTypeSp, new GUIContent("Microphone Type",
                                                                                        "Which microphone API to use when the Source is set to Microphone."));
                    EditorGUILayout.HelpBox("Devices list and current selection is valid in Unity Editor only. In build, you need to set it via code preferably at runtime.", MessageType.Info);
                    switch (recorder.MicrophoneType)
                    {
                    case Recorder.MicType.Unity:
                        if (Microphone.devices.Length == 0)
                        {
                            EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                        }
                        else
                        {
                            unityMicrophoneDeviceIndex = EditorGUILayout.Popup("Microphone Device", unityMicrophoneDeviceIndex, Microphone.devices);
                            this.unityMicrophoneDeviceSp.stringValue = Microphone.devices[unityMicrophoneDeviceIndex];
                            int minFreq, maxFreq;
                            Microphone.GetDeviceCaps(Microphone.devices[unityMicrophoneDeviceIndex], out minFreq, out maxFreq);
                            EditorGUILayout.LabelField("Microphone Device Caps", string.Format("{0}..{1} Hz", minFreq, maxFreq));
                        }
                        break;

                    case Recorder.MicType.Photon:
                                #if PHOTON_MICROPHONE_ENUMERATOR
                        if (Recorder.PhotonMicrophoneEnumerator.IsSupported)
                        {
                            if (Recorder.PhotonMicrophoneEnumerator.Count == 0)
                            {
                                EditorGUILayout.HelpBox("No microphone device found", MessageType.Error);
                            }
                            else
                            {
                                EditorGUILayout.BeginHorizontal();
                                photonDeviceIndex = EditorGUILayout.Popup("Microphone Device", photonDeviceIndex, photonDeviceNames);
                                this.photonMicrophoneDeviceIdSp.intValue = photonDeviceIDs[photonDeviceIndex];
                                if (GUILayout.Button("Refresh", EditorStyles.miniButton, GUILayout.Width(70)))
                                {
                                    this.RefreshPhotonMicrophoneDevices();
                                }
                                EditorGUILayout.EndHorizontal();
                            }
                        }
                        else
                        {
                            recorder.PhotonMicrophoneDeviceId = -1;
                            EditorGUILayout.HelpBox("PhotonMicrophoneEnumerator Not Supported", MessageType.Error);
                        }
                                #endif
                                #if UNITY_IOS
                        EditorGUILayout.LabelField("iOS Audio Session Parameters", EditorStyles.boldLabel);
                        EditorGUI.indentLevel++;
                        EditorGUILayout.PropertyField(useCustomAudioSessionParametersSp, new GUIContent("Use Custom"));
                        if (useCustomAudioSessionParametersSp.boolValue)
                        {
                            EditorGUILayout.PropertyField(audioSessionParametersCategorySp);
                            EditorGUILayout.PropertyField(audioSessionParametersModeSp);
                            EditorGUILayout.PropertyField(audioSessionParametersCategoryOptionsSp, true);
                        }
                        else
                        {
                            int index = EditorGUILayout.Popup("Preset", audioSessionPresetIndexSp.intValue, iOSAudioSessionPresetsNames);
                            if (index != audioSessionPresetIndexSp.intValue)
                            {
                                audioSessionPresetIndexSp.intValue = index;
                                AudioSessionParameters parameters = iOSAudioSessionPresetsValues[index];
                                this.SetEnumIndex(audioSessionParametersCategorySp,
                                                  typeof(AudioSessionCategory), parameters.Category);
                                this.SetEnumIndex(audioSessionParametersModeSp,
                                                  typeof(AudioSessionMode), parameters.Mode);
                                if (parameters.CategoryOptions != null)
                                {
                                    audioSessionParametersCategoryOptionsSp.ClearArray();
                                    audioSessionParametersCategoryOptionsSp.arraySize =
                                        parameters.CategoryOptions.Length;
                                    if (index == 0)
                                    {
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.DefaultToSpeaker);
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(1), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                    else if (index == 1)
                                    {
                                        this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                          .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                    }
                                }
                            }
                        }
                        EditorGUI.indentLevel--;
                                #endif
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;

                case Recorder.InputSourceType.AudioClip:
                    EditorGUILayout.PropertyField(this.audioClipSp,
                                                  new GUIContent("Audio Clip", "Source audio clip."));
                    EditorGUILayout.PropertyField(this.loopAudioClipSp,
                                                  new GUIContent("Loop", "Loop playback for audio clip sources."));
                    break;

                case Recorder.InputSourceType.Factory:
                    EditorGUILayout.HelpBox("Add a custom InputFactory method in code.", MessageType.Info);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                EditorGUILayout.LabelField("Voice Activity Detection (VAD)", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(this.voiceDetectionSp,
                                              new GUIContent("Detect", "If true, voice detection enabled."));
                if (this.voiceDetectionSp.boolValue)
                {
                    this.voiceDetectionThresholdSp.floatValue = EditorGUILayout.Slider(
                        new GUIContent("Threshold", "Voice detection threshold (0..1, where 1 is full amplitude)."),
                        this.voiceDetectionThresholdSp.floatValue, 0f, 1f);
                    this.voiceDetectionDelayMsSp.intValue =
                        EditorGUILayout.IntField(new GUIContent("Delay (ms)", "Keep detected state during this time after signal level dropped below threshold. Default is 500ms"), this.voiceDetectionDelayMsSp.intValue);
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
        }
Example #3
0
        public override void OnInspectorGUI()
        {
            // serializedObject.UpdateIfRequiredOrScript()
            if (Application.isPlaying)
            {
                if (recorder.RequiresRestart)
                {
                    EditorGUILayout.HelpBox("Recorder requires restart. Call Recorder.RestartRecording().", MessageType.Warning);
                    if (GUILayout.Button("RestartRecording"))
                    {
                        recorder.RestartRecording();
                    }
                }
                else if (!recorder.IsInitialized)
                {
                    EditorGUILayout.HelpBox("Recorder requires initialization. Call Recorder.Init(VoiceClient, Object).", MessageType.Warning);
                }
            }
            VoiceLogger.ExposeLogLevel(serializedObject, recorder);
            EditorGUI.BeginChangeCheck();
            recorder.ReactOnSystemChanges = EditorGUILayout.Toggle(new GUIContent("React On System Changes", "If true, recording is restarted when Unity detects Audio Config. changes."), recorder.ReactOnSystemChanges);
            recorder.AutoStart            = EditorGUILayout.Toggle(new GUIContent("Auto Start", "If true, recording is started when Recorder is initialized."), recorder.AutoStart);
            recorder.TransmitEnabled      = EditorGUILayout.Toggle(new GUIContent("Transmit Enabled", "If true, audio transmission is enabled."), recorder.TransmitEnabled);
            if (recorder.IsInitialized)
            {
                recorder.IsRecording = EditorGUILayout.Toggle(new GUIContent("IsRecording", "If true, audio recording is on."), recorder.IsRecording);
            }
            if (recorder.IsRecording)
            {
                float amplitude = 0f;
                if (recorder.IsCurrentlyTransmitting)
                {
                    amplitude = recorder.LevelMeter.CurrentPeakAmp;
                    if (amplitude > 1f)
                    {
                        amplitude /= 32768;
                    }
                }
                EditorGUILayout.Slider("Level", amplitude, 0, 1);
            }
            recorder.Encrypt       = EditorGUILayout.Toggle(new GUIContent("Encrypt", "If true, voice stream is sent encrypted."), recorder.Encrypt);
            recorder.InterestGroup = (byte)EditorGUILayout.IntField(new GUIContent("Interest Group", "Target interest group that will receive transmitted audio."), recorder.InterestGroup);
            if (recorder.InterestGroup == 0)
            {
                recorder.DebugEchoMode = EditorGUILayout.Toggle(new GUIContent("Debug Echo", "If true, outgoing stream routed back to client via server same way as for remote client's streams."), recorder.DebugEchoMode);
            }

            recorder.ReliableMode = EditorGUILayout.Toggle(new GUIContent("Reliable Mode", "If true, stream data sent in reliable mode."), recorder.ReliableMode);

            EditorGUILayout.LabelField("Codec Parameters", EditorStyles.boldLabel);
            recorder.FrameDuration = (OpusCodec.FrameDuration)EditorGUILayout.EnumPopup(new GUIContent("Frame Duration", "Outgoing audio stream encoder delay."), recorder.FrameDuration);
            recorder.SamplingRate  = (POpusCodec.Enums.SamplingRate)EditorGUILayout.EnumPopup(
                new GUIContent("Sampling Rate", "Outgoing audio stream sampling rate."), recorder.SamplingRate);
            recorder.Bitrate = EditorGUILayout.IntField(new GUIContent("Bitrate", "Outgoing audio stream bitrate."),
                                                        recorder.Bitrate);

            EditorGUILayout.LabelField("Audio Source Settings", EditorStyles.boldLabel);
            recorder.SourceType = (Recorder.InputSourceType)EditorGUILayout.EnumPopup(new GUIContent("Input Source Type", "Input audio data source type"), recorder.SourceType);
            switch (recorder.SourceType)
            {
            case Recorder.InputSourceType.Microphone:
                recorder.MicrophoneType = (Recorder.MicType)EditorGUILayout.EnumPopup(
                    new GUIContent("Microphone Type",
                                   "Which microphone API to use when the Source is set to Microphone."),
                    recorder.MicrophoneType);
                switch (recorder.MicrophoneType)
                {
                case Recorder.MicType.Unity:
                    unityMicrophoneDeviceIndex     = EditorGUILayout.Popup("Microphone Device", unityMicrophoneDeviceIndex, Microphone.devices);
                    recorder.UnityMicrophoneDevice = Microphone.devices[unityMicrophoneDeviceIndex];
                    int minFreq, maxFreq;
                    Microphone.GetDeviceCaps(Microphone.devices[unityMicrophoneDeviceIndex], out minFreq, out maxFreq);
                    EditorGUILayout.LabelField("Microphone Device Caps", string.Format("{0}..{1} Hz", minFreq, maxFreq));
                    break;

                case Recorder.MicType.Photon:
                            #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
                    if (Recorder.PhotonMicrophoneEnumerator.IsSupported)
                    {
                        recorder.PhotonMicrophoneDeviceId = EditorGUILayout.Popup("Microphone Device",
                                                                                  recorder.PhotonMicrophoneDeviceId, photonDeviceNames);
                    }
                    else
                    {
                        recorder.PhotonMicrophoneDeviceId = -1;
                        EditorGUILayout.HelpBox("PhotonMicrophoneEnumerator Not Supported", MessageType.Error);
                    }
                            #endif
                            #if UNITY_IOS
                    EditorGUILayout.LabelField("iOS Audio Session Parameters", EditorStyles.boldLabel);
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(useCustomAudioSessionParametersSp, new GUIContent("Use Custom"));
                    if (useCustomAudioSessionParametersSp.boolValue)
                    {
                        EditorGUILayout.PropertyField(audioSessionParametersCategorySp);
                        EditorGUILayout.PropertyField(audioSessionParametersModeSp);
                        EditorGUILayout.PropertyField(audioSessionParametersCategoryOptionsSp, true);
                    }
                    else
                    {
                        int index = EditorGUILayout.Popup("Preset", audioSessionPresetIndexSp.intValue, iOSAudioSessionPresetsNames);
                        if (index != audioSessionPresetIndexSp.intValue)
                        {
                            audioSessionPresetIndexSp.intValue = index;
                            AudioSessionParameters parameters = iOSAudioSessionPresetsValues[index];
                            //recorder.SetIosAudioSessionParameters(parameters);
                            this.SetEnumIndex(audioSessionParametersCategorySp,
                                              typeof(AudioSessionCategory), parameters.Category);
                            this.SetEnumIndex(audioSessionParametersModeSp,
                                              typeof(AudioSessionMode), parameters.Mode);
                            if (parameters.CategoryOptions != null)
                            {
                                audioSessionParametersCategoryOptionsSp.ClearArray();
                                audioSessionParametersCategoryOptionsSp.arraySize =
                                    parameters.CategoryOptions.Length;
                                // somehow this won't work and parameters.CategoryOptions[i] is always 0
                                //for (int i = 0; i < parameters.CategoryOptions.Length; i++)
                                //{
                                //    this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                //        .GetArrayElementAtIndex(i), typeof(AudioSessionCategoryOption), parameters.CategoryOptions[i]);
                                //}
                                if (index == 0)
                                {
                                    this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                      .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.DefaultToSpeaker);
                                    this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                      .GetArrayElementAtIndex(1), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                }
                                else if (index == 1)
                                {
                                    this.SetEnumIndex(audioSessionParametersCategoryOptionsSp
                                                      .GetArrayElementAtIndex(0), typeof(AudioSessionCategoryOption), AudioSessionCategoryOption.AllowBluetooth);
                                }
                            }
                        }
                    }
                    EditorGUI.indentLevel--;
                            #endif
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                break;

            case Recorder.InputSourceType.AudioClip:
                recorder.AudioClip     = EditorGUILayout.ObjectField(new GUIContent("Audio Clip", "Source audio clip."), recorder.AudioClip, typeof(AudioClip), false) as AudioClip;
                recorder.LoopAudioClip =
                    EditorGUILayout.Toggle(new GUIContent("Loop", "Loop playback for audio clip sources."),
                                           recorder.LoopAudioClip);
                break;

            case Recorder.InputSourceType.Factory:
                EditorGUILayout.HelpBox("Add a custom InputFactory method in code.", MessageType.Info);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            recorder.TypeConvert = (Recorder.SampleTypeConv)EditorGUILayout.EnumPopup(
                new GUIContent("Type Convert",
                               "Force creation of 'short' pipeline and convert audio data to short for 'float' audio sources."),
                recorder.TypeConvert);
            EditorGUILayout.LabelField("Voice Activity Detection (VAD)", EditorStyles.boldLabel);
            recorder.VoiceDetection = EditorGUILayout.Toggle(new GUIContent("Detect", "If true, voice detection enabled."), recorder.VoiceDetection);
            if (recorder.VoiceDetection)
            {
                recorder.VoiceDetectionThreshold =
                    EditorGUILayout.FloatField(new GUIContent("Threshold", "Voice detection threshold (0..1, where 1 is full amplitude)."), recorder.VoiceDetectionThreshold);
                recorder.VoiceDetectionDelayMs =
                    EditorGUILayout.IntField(new GUIContent("Delay (ms)", "Keep detected state during this time after signal level dropped below threshold. Default is 500ms"), recorder.VoiceDetectionDelayMs);
                if (recorder.VoiceDetectorCalibrating)
                {
                    EditorGUILayout.LabelField(string.Format("Calibrating {0} ms", calibrationTime));
                }
                else
                {
                    calibrationTime = EditorGUILayout.IntField("Calibration Time (ms)", calibrationTime);
                    if (recorder.IsRecording)
                    {
                        if (GUILayout.Button("Calibrate"))
                        {
                            recorder.VoiceDetectorCalibrate(calibrationTime);
                        }
                    }
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
        }