287 lines
15 KiB
C#
287 lines
15 KiB
C#
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX || UNITY_SWITCH || UNITY_IOS
|
|
#define PHOTON_AUDIO_CHANGE_IN_NOTIFIER
|
|
#endif
|
|
|
|
namespace Photon.Voice.Unity {
|
|
using Voice;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// This component is useful to handle audio device and config changes.
|
|
/// </summary>
|
|
[RequireComponent(typeof(Recorder))]
|
|
public class AudioChangesHandler : VoiceComponent {
|
|
private IAudioInChangeNotifier photonMicChangeNotifier;
|
|
private AudioConfiguration audioConfiguration;
|
|
private Recorder recorder;
|
|
|
|
/// <summary>
|
|
/// Try to start recording when we get devices change notification and recording is not started.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// On some platforms we can't make sure that a device change notification could mean that at least a microphone device is now available.
|
|
/// Besides, the auto start of the recording might not happen if other necessary conditions set in Recorder are not met:
|
|
/// e.g. <see cref="Recorder.RecordOnlyWhenEnabled"/> or <see cref="Recorder.RecordOnlyWhenJoined"/> etc.
|
|
/// or if the Recorder has been stopped explicitly via <see cref="Recorder.StopRecording"/> call or <see cref="Recorder.IsRecording"/> set to false.
|
|
/// </remarks>
|
|
[Tooltip("Try to start recording when we get devices change notification and recording is not started.")]
|
|
public bool StartWhenDeviceChange = true;
|
|
/// <summary>
|
|
/// Try to react to device change notification when Recorder is started.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This requires <see cref="UseNativePluginChangeNotifier"/> or <see cref="UseOnAudioConfigurationChanged"/> to be true.
|
|
/// </remarks>
|
|
[Tooltip("Try to react to device change notification when Recorder is started.")]
|
|
public bool HandleDeviceChange = true;
|
|
/// <summary>
|
|
/// Try to react to audio config change notification when Recorder is started.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This requires <see cref="UseOnAudioConfigurationChanged"/> to be true.
|
|
/// </remarks>
|
|
[Tooltip("Try to react to audio config change notification when Recorder is started.")]
|
|
public bool HandleConfigChange = true;
|
|
/// <summary>
|
|
/// Whether or not to make use of Photon's AudioInChangeNotifier native plugin.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This may disable <see cref="HandleDeviceChange"/> if this and <see cref="UseOnAudioConfigurationChanged"/> are both false.
|
|
/// </remarks>
|
|
[Tooltip("Whether or not to make use of Photon's AudioInChangeNotifier native plugin.")]
|
|
public bool UseNativePluginChangeNotifier = true;
|
|
/// <summary>
|
|
/// Whether or not to make use of Unity's OnAudioConfigurationChanged.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is needed for <see cref="HandleConfigChange"/> and may also disable
|
|
/// <see cref="HandleDeviceChange"/> if this and <see cref="UseNativePluginChangeNotifier"/> are both false.
|
|
/// </remarks>
|
|
[Tooltip("Whether or not to make use of Unity's OnAudioConfigurationChanged.")]
|
|
public bool UseOnAudioConfigurationChanged = true;
|
|
|
|
#if UNITY_EDITOR || UNITY_ANDROID
|
|
/// <summary>
|
|
/// If the recorder is set to use microphone as source with type Photon, audio device changes are handled within the native plugin by default.
|
|
/// If you set this to true, it will also be handled via this component logic.
|
|
/// </summary>
|
|
[Tooltip("If the recorder is set to use microphone as source with type Photon, audio device changes are handled within the native plugin by default. " +
|
|
"If you set this to true, it will also be handled via this component logic.")]
|
|
public bool Android_AlwaysHandleDeviceChange;
|
|
#endif
|
|
#if UNITY_EDITOR || UNITY_IOS
|
|
/// <summary>
|
|
/// If the recorder is set to use microphone as source with type Photon, audio device changes are handled within the native plugin by default.
|
|
/// If you set this to true, it will also be handled via this component logic.
|
|
/// </summary>
|
|
[Tooltip("If the recorder is set to use microphone as source with type Photon, audio device changes are handled within the native plugin by default. " +
|
|
"If you set this to true, it will also be handled via this component logic.")]
|
|
public bool iOS_AlwaysHandleDeviceChange;
|
|
#endif
|
|
|
|
private bool subscribedToSystemChangesPhoton, subscribedToSystemChangesUnity;
|
|
|
|
protected override void Awake() {
|
|
base.Awake();
|
|
this.recorder = this.GetComponent<Recorder>();
|
|
this.recorder.ReactOnSystemChanges = false;
|
|
//if (this.recorder.AutoStart) {
|
|
// if (this.AutoStartWhenMicrophoneMightBeAvailable && this.CheckIfMicrophoneIsAvailable) {
|
|
// this.recorder.AutoStart = false;
|
|
// if (this.micAvailable) {
|
|
// this.recorder.CheckAndAutoStart(true);
|
|
// }
|
|
// } else if (this.recorder.IsRecording) {
|
|
// this.recorder.AutoStart = false;
|
|
// }
|
|
//}
|
|
this.audioConfiguration = AudioSettings.GetConfiguration();
|
|
this.SubscribeToSystemChanges();
|
|
}
|
|
|
|
private void OnDestroy() {
|
|
this.UnsubscribeFromSystemChanges();
|
|
}
|
|
|
|
#if PHOTON_AUDIO_CHANGE_IN_NOTIFIER
|
|
private void PhotonMicrophoneChangeDetected() {
|
|
if (this.Logger.IsDebugEnabled) {
|
|
this.Logger.LogDebug("Microphones change detected by Photon native plugin.");
|
|
}
|
|
if (!this.recorder.MicrophoneDeviceChangeDetected && this.UseNativePluginChangeNotifier) {
|
|
this.OnDeviceChange();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private void OnDeviceChange() {
|
|
if (!this.recorder.IsRecording) {
|
|
if (this.StartWhenDeviceChange) {
|
|
this.recorder.MicrophoneDeviceChangeDetected = true;
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("An attempt to auto start recording should follow shortly.");
|
|
}
|
|
} else if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Device change detected but will not try to start recording as StartWhenDeviceChange is false.");
|
|
}
|
|
} else if (this.HandleDeviceChange) {
|
|
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)
|
|
if (this.recorder.SourceType == Recorder.InputSourceType.Microphone && this.recorder.MicrophoneType == Recorder.MicType.Photon) {
|
|
#if UNITY_ANDROID
|
|
if (!this.Android_AlwaysHandleDeviceChange) {
|
|
#elif UNITY_IOS
|
|
if (!this.iOS_AlwaysHandleDeviceChange) {
|
|
#endif
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Device change notification ignored when using Photon microphone type as this is handled internally for iOS and Android via native plugins.");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
this.recorder.MicrophoneDeviceChangeDetected = true;
|
|
} else if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Device change detected but will not try to handle this as HandleDeviceChange is false.");
|
|
}
|
|
}
|
|
|
|
private void SubscribeToSystemChanges() {
|
|
if (this.Logger.IsDebugEnabled) {
|
|
this.Logger.LogDebug("Subscribing to system (audio) changes.");
|
|
}
|
|
#if PHOTON_AUDIO_CHANGE_IN_NOTIFIER
|
|
if (this.subscribedToSystemChangesPhoton) {
|
|
if (this.Logger.IsWarningEnabled) {
|
|
this.Logger.LogWarning("Already subscribed to audio changes via Photon.");
|
|
}
|
|
} else {
|
|
this.photonMicChangeNotifier = Platform.CreateAudioInChangeNotifier(this.PhotonMicrophoneChangeDetected, this.Logger);
|
|
if (this.photonMicChangeNotifier.IsSupported) {
|
|
if (this.photonMicChangeNotifier.Error == null) {
|
|
this.subscribedToSystemChangesPhoton = true;
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Subscribed to audio in change notifications via Photon plugin.");
|
|
}
|
|
}
|
|
if (this.Logger.IsErrorEnabled) {
|
|
this.Logger.LogError("Error creating instance of photonMicChangeNotifier: {0}", this.photonMicChangeNotifier.Error);
|
|
}
|
|
} else if (this.Logger.IsErrorEnabled) {
|
|
this.Logger.LogError("Unexpected: Photon's AudioInChangeNotifier not supported on current platform: {0}", CurrentPlatform);
|
|
}
|
|
if (!this.subscribedToSystemChangesPhoton) {
|
|
this.photonMicChangeNotifier.Dispose();
|
|
this.photonMicChangeNotifier = null;
|
|
}
|
|
}
|
|
#else
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Skipped subscribing to audio change notifications via Photon's AudioInChangeNotifier as not supported on current platform: {0}", CurrentPlatform);
|
|
}
|
|
if (this.subscribedToSystemChangesPhoton) {
|
|
if (this.Logger.IsErrorEnabled) {
|
|
this.Logger.LogError("Unexpected: subscribedToSystemChangesPhoton is set to true while platform is not supported!.");
|
|
}
|
|
}
|
|
#endif
|
|
if (this.subscribedToSystemChangesUnity) {
|
|
if (this.Logger.IsWarningEnabled) {
|
|
this.Logger.LogWarning("Already subscribed to audio changes via Unity OnAudioConfigurationChanged callback.");
|
|
}
|
|
} else {
|
|
AudioSettings.OnAudioConfigurationChanged += this.OnAudioConfigChanged;
|
|
this.subscribedToSystemChangesUnity = true;
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Subscribed to audio configuration changes via Unity OnAudioConfigurationChanged callback.");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnAudioConfigChanged(bool deviceWasChanged) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: {0}", deviceWasChanged ? "Device was changed." : "AudioSettings.Reset was called.");
|
|
}
|
|
AudioConfiguration config = AudioSettings.GetConfiguration();
|
|
bool audioConfigChanged = false;
|
|
if (config.dspBufferSize != this.audioConfiguration.dspBufferSize) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: dspBufferSize old={0} new={1}", this.audioConfiguration.dspBufferSize, config.dspBufferSize);
|
|
}
|
|
audioConfigChanged = true;
|
|
}
|
|
if (config.numRealVoices != this.audioConfiguration.numRealVoices) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: numRealVoices old={0} new={1}", this.audioConfiguration.numRealVoices, config.numRealVoices);
|
|
}
|
|
audioConfigChanged = true;
|
|
}
|
|
if (config.numVirtualVoices != this.audioConfiguration.numVirtualVoices) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: numVirtualVoices old={0} new={1}", this.audioConfiguration.numVirtualVoices, config.numVirtualVoices);
|
|
}
|
|
audioConfigChanged = true;
|
|
}
|
|
if (config.sampleRate != this.audioConfiguration.sampleRate) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: sampleRate old={0} new={1}", this.audioConfiguration.sampleRate, config.sampleRate);
|
|
}
|
|
audioConfigChanged = true;
|
|
}
|
|
if (config.speakerMode != this.audioConfiguration.speakerMode) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("OnAudioConfigurationChanged: speakerMode old={0} new={1}", this.audioConfiguration.speakerMode, config.speakerMode);
|
|
}
|
|
audioConfigChanged = true;
|
|
}
|
|
if (audioConfigChanged) {
|
|
this.audioConfiguration = config;
|
|
}
|
|
if (!this.recorder.MicrophoneDeviceChangeDetected) {
|
|
if (audioConfigChanged) {
|
|
if (this.recorder.IsRecording) {
|
|
if (this.HandleConfigChange) {
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Config change detected; an attempt to auto start recording should follow shortly.");
|
|
}
|
|
this.recorder.MicrophoneDeviceChangeDetected = true;
|
|
} else if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Config change detected but will not try to handle this as HandleConfigChange is false.");
|
|
}
|
|
} else if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Config change detected but ignored as recording not started.");
|
|
}
|
|
} else if (deviceWasChanged) {
|
|
if (this.UseOnAudioConfigurationChanged) {
|
|
this.OnDeviceChange();
|
|
} else if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Device change detected but will not try to handle this as UseOnAudioConfigurationChanged is false.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnsubscribeFromSystemChanges() {
|
|
if (this.subscribedToSystemChangesUnity) {
|
|
AudioSettings.OnAudioConfigurationChanged -= this.OnAudioConfigChanged;
|
|
this.subscribedToSystemChangesUnity = false;
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Unsubscribed from audio changes via Unity OnAudioConfigurationChanged callback.");
|
|
}
|
|
}
|
|
if (this.subscribedToSystemChangesPhoton) {
|
|
if (this.photonMicChangeNotifier == null) {
|
|
if (this.Logger.IsErrorEnabled) {
|
|
this.Logger.LogError("Unexpected: photonMicChangeNotifier is null while subscribedToSystemChangesPhoton is true.");
|
|
}
|
|
} else {
|
|
this.photonMicChangeNotifier.Dispose();
|
|
this.photonMicChangeNotifier = null;
|
|
}
|
|
this.subscribedToSystemChangesPhoton = false;
|
|
if (this.Logger.IsInfoEnabled) {
|
|
this.Logger.LogInfo("Unsubscribed from audio in change notifications via Photon plugin.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |