// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) (2018-2022) Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% namespace UnityEngine.XR.MagicLeap { using System; using System.Runtime.InteropServices; using UnityEngine.XR.MagicLeap.Native; /// /// Manages Audio. /// public sealed partial class MLAudioInput : MLAutoAPISingleton { /// /// The mute state of the microphone. /// private bool isMicrophoneMuted; /// /// The delegate for the microphone mute changed event. /// /// The new mute state of the microphone. public delegate void OnMicrophoneMuteChangedDelegate(bool muted); /// /// Raised whenever the global microphone mute gets changed. /// public static event OnMicrophoneMuteChangedDelegate OnMicrophoneMuteChanged = delegate { }; /// /// Gets or sets a value indicating whether the microphone is muted. /// public static bool MicrophoneMuted { get { return Instance.isMicrophoneMuted; } set { Instance.InternalSetMicMute(value); } } /// /// Gets the result string for a MLResult.Code. /// /// The MLResult.Code to be requested. /// A pointer to the result string. internal static IntPtr GetResultString(MLResult.Code result) { nativeGetResultStringPerfMarker.Begin(); IntPtr ptr = NativeBindings.MLAudioGetResultString(result); nativeGetResultStringPerfMarker.End(); return ptr; } #if !DOXYGEN_SHOULD_SKIP_THIS /// /// Called by MLAutoAPISingleton to start the API /// /// /// MLResult.Result will be MLResult.Code.Ok if successful. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if failed due to internal error. /// MLResult.Result will be MLResult.Code.InvalidParam if a parameter is invalid. /// MLResult.Result will be MLResult.Code.PermissionDenied if AudioCaptureMic permission is denied. /// MLResult.Result will be MLResult.Code.AudioNotImplemented if the function is not implemented. /// protected override MLResult.Code StartAPI() { startAPIPerfMarker.Begin(); MLResult.Code resultCode; // Microphone Muted Callback resultCode = this.RegisterOnMicrophoneMuteCallback(); if (resultCode != MLResult.Code.Ok) { startAPIPerfMarker.End(); return resultCode; } // Get the initial IsMicrophoneMuted value. resultCode = Instance.GetMicrophoneMuted(out this.isMicrophoneMuted); if (resultCode != MLResult.Code.Ok) { startAPIPerfMarker.End(); return resultCode; } startAPIPerfMarker.End(); return resultCode; } #endif // DOXYGEN_SHOULD_SKIP_THIS /// /// Called by MLAutoAPISingleton on destruction /// protected override MLResult.Code StopAPI() => this.UnregisterOnMicrophoneMuteCallback(); /// /// Called every device frame /// protected override void Update() { } /// /// Handles the callback for MLAudioSetMicMute. /// /// The mute state of the microphone. /// A pointer to the callback. [AOT.MonoPInvokeCallback(typeof(NativeBindings.MLAudioMicMuteCallback))] private static void HandleOnMLAudioSetMicMuteCallback([MarshalAs(UnmanagedType.I1)] bool isMuted, IntPtr callback) { Instance.isMicrophoneMuted = isMuted; MLThreadDispatch.Call(isMuted, OnMicrophoneMuteChanged); } /// /// Returns the mute state of the microphone. /// /// The mute state of the microphone. /// /// MLResult.Result will be MLResult.Code.Ok if successful. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if failed due to internal error. /// MLResult.Result will be MLResult.Code.InvalidParam if a parameter is invalid. /// MLResult.Result will be MLResult.Code.PermissionDenied if AudioCaptureMic permission is denied. /// MLResult.Result will be MLResult.Code.AudioNotImplemented if the function is not implemented. /// private MLResult.Code GetMicrophoneMuted(out bool isMuted) { MLResult.Code result; try { nativeIsMicMutedPerfMarker.Begin(); result = NativeBindings.MLAudioGetMicMute(out isMuted); MLResult.DidNativeCallSucceed(result, nameof(NativeBindings.MLAudioGetMicMute)); nativeIsMicMutedPerfMarker.End(); if (result != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLAudioInput.GetMicrophoneMuted failed to get the value. Reason: {0}", result); } } catch (System.DllNotFoundException) { // Exception is caught in the Singleton BaseStart(). throw; } return result; } /// /// Registers a callback for the device microphone mute change event. /// /// /// MLResult.Result will be MLResult.Code.Ok if successful. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if failed due to internal error. /// MLResult.Result will be MLResult.Code.InvalidParam if a parameter is invalid. /// MLResult.Result will be MLResult.Code.PermissionDenied if AudioCaptureMic permission is denied. /// MLResult.Result will be MLResult.Code.AudioNotImplemented if the function is not implemented. /// private MLResult.Code RegisterOnMicrophoneMuteCallback() { MLResult.Code result; try { nativeSetMicMuteCallbackPerfMarker.Begin(); // Attempt to register the native callback for the volume change event. result = NativeBindings.MLAudioSetMicMuteCallback(HandleOnMLAudioSetMicMuteCallback, IntPtr.Zero); nativeSetMicMuteCallbackPerfMarker.End(); if (result != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLAudioInput.RegisterOnAudioSetMicMuteCallback failed to register callback. Reason: {0}", result); } } catch (System.DllNotFoundException) { // Exception is caught in the Singleton BaseStart(). throw; } return result; } /// /// Unregisters a previously registered callback for the device microphone mute change event. /// /// /// MLResult.Result will be MLResult.Code.Ok if successful. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if failed due to internal error. /// MLResult.Result will be MLResult.Code.InvalidParam if a parameter is invalid. /// MLResult.Result will be MLResult.Code.PermissionDenied if AudioCaptureMic permission is denied. /// MLResult.Result will be MLResult.Code.AudioNotImplemented if the function is not implemented. /// private MLResult.Code UnregisterOnMicrophoneMuteCallback() { MLResult.Code result; try { nativeSetMicMuteCallbackPerfMarker.Begin(); // Unregister the native callback for the microphone mute change event. result = NativeBindings.MLAudioSetMicMuteCallback(null, IntPtr.Zero); nativeSetMicMuteCallbackPerfMarker.End(); if (result != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLAudioInput.UnregisterOnMicrophoneMuteCallback failed to register callback. Reason: {0}", result); } } catch (System.DllNotFoundException) { MLPluginLog.Error(MLResult.Code.APIDLLNotFound); throw; } return result; } /// /// Sets the mute state of the microphone. /// /// The microphone mute state. private void InternalSetMicMute(bool mute) { try { nativeSetMicMutePerfMarker.Begin(); MLResult.Code result = NativeBindings.MLAudioSetMicMute(mute); nativeSetMicMutePerfMarker.End(); if (result != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLAudioInput.InternalSetMicMute failed to set the value. Reason: {0}", result); } this.isMicrophoneMuted = mute; } catch (System.DllNotFoundException) { MLPluginLog.Error(MLResult.Code.APIDLLNotFound); throw; } } } }