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(); } }
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(); } }