[AudioManager] Add new SoundEffect APIs (#6329)
authorHaesu Gwon <haesu.gwon@samsung.com>
Fri, 13 Sep 2024 03:38:15 +0000 (12:38 +0900)
committerGitHub <noreply@github.com>
Fri, 13 Sep 2024 03:38:15 +0000 (12:38 +0900)
src/Tizen.Multimedia/AudioManager/AudioStreamPolicy.cs
src/Tizen.Multimedia/AudioManager/SoundEffect.cs [new file with mode: 0644]
src/Tizen.Multimedia/Interop/Interop.StreamPolicy.cs

index 9d450f638bb63cc5d0546d229c0cdb8d8adec9e2..0d8ada32706ef899f8f78643fa23a375ee3030bc 100644 (file)
@@ -15,7 +15,9 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.Diagnostics;
+using System.Linq;
 
 namespace Tizen.Multimedia
 {
@@ -421,6 +423,104 @@ namespace Tizen.Multimedia
             return isOn;
         }
 
+        /// <summary>
+        /// Sets the sound effect.
+        /// </summary>
+        /// <remarks>
+        /// If <paramref name="withReference"/> is true, <paramref name="info.Type"/> must be <see cref="SoundEffectType.ReferenceCopy"/> or
+        /// <see cref="SoundEffectType.AecSpeex"/> or <see cref="SoundEffectType.AecWebrtc"/>.
+        /// And <paramref name="info.ReferenceDevice"/> must not be null.<br/>
+        /// If <paramref name="withReference"/> is false, <paramref name="info.Type"/> must be <see cref="SoundEffectType.NoiseSuppression"/> or
+        /// <see cref="SoundEffectType.AutoGainControl"/> or <see cref="SoundEffectType.NsWithAgc"/>.
+        /// </remarks>
+        /// <param name="info">See <see cref="SoundEffectInfo"/>.</param>
+        /// <param name="withReference">A reference device for sound effect.</param>
+        /// <exception cref="ArgumentNullException">When <paramref name="withReference"/> is true, A reference device is null.</exception>
+        /// <exception cref="AudioPolicyException">The current <see cref="AudioStreamType"/> is not supported for sound effect with reference.</exception>
+        /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public void SetSoundEffect(SoundEffectInfo info, bool withReference)
+        {
+            if (withReference)
+            {
+                var set = new SoundEffectType[] { SoundEffectType.ReferenceCopy, SoundEffectType.AecSpeex, SoundEffectType.AecWebrtc };
+                if (!set.Contains(info.Type))
+                {
+                    Log.Error(Tag, $"Type={info.Type} is not supported for setting with reference.");
+                    throw new ArgumentException($"{info.Type} is not supported for setting with reference.");
+                }
+                if (info.ReferenceDevice == null)
+                {
+                    throw new ArgumentNullException(nameof(info.ReferenceDevice));
+                }
+
+                Log.Info(Tag, $"{info.ReferenceDevice}");
+
+                Interop.AudioStreamPolicy.SetSoundEffectWithReference(Handle, (SoundEffectWithReferenceNative)info.Type.ToNative(),
+                    info.ReferenceDevice.Id).ThrowIfError("Failed to set audio effect with reference");
+            }
+            else
+            {
+                var set = new SoundEffectType[] { SoundEffectType.NoiseSuppression, SoundEffectType.AutoGainControl, SoundEffectType.NsWithAgc };
+                if (!set.Contains(info.Type))
+                {
+                    throw new ArgumentException($"{info.Type} is not supported for setting without reference.");
+                }
+
+                Interop.AudioStreamPolicy.SetSoundEffect(Handle, info.Type.ToNative()).
+                    ThrowIfError("Failed to set sound effect with reference");
+            }
+        }
+
+        /// <summary>
+        /// Gets the sound effect.
+        /// </summary>
+        /// <remarks>
+        /// If <paramref name="withReference"/> is false, <see cref="SoundEffectInfo.ReferenceDevice"/> of returned value will be null.
+        /// </remarks>
+        /// <exception cref="InvalidOperationException">
+        /// The sound effect is not set yet.<br/>
+        /// - or -<br/>
+        /// There's no matched AudioDevice.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">Sound effect is not set yet.</exception>
+        /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public SoundEffectInfo GetSoundEffect(bool withReference)
+        {
+            AudioManagerError ret = AudioManagerError.None;
+            SoundEffectInfo soundEffectInfo;
+            int deviceId = 0;
+
+            if (withReference)
+            {
+                ret = Interop.AudioStreamPolicy.GetSoundEffectWithReference(Handle, out SoundEffectWithReferenceNative nativeEffect, out deviceId);
+                if (ret == AudioManagerError.InvalidParameter)
+                {
+                    throw new InvalidOperationException("There's no sound effect with reference");
+                }
+                ret.ThrowIfError("Failed to get sound effect with reference");
+
+                Log.Info(Tag, $"Device ID : {deviceId}");
+
+                soundEffectInfo = new SoundEffectInfo(nativeEffect.ToPublic(),
+                    AudioManager.GetConnectedDevices().Where(d => d.Id == deviceId).Single());
+            }
+            else
+            {
+                ret = Interop.AudioStreamPolicy.GetSoundEffect(Handle, out int nativeEffect);
+                if (ret == AudioManagerError.InvalidParameter)
+                {
+                    throw new InvalidOperationException("There's no sound effect");
+                }
+                ret.ThrowIfError("Failed to get sound effect");
+
+                soundEffectInfo = new SoundEffectInfo(((SoundEffectNative)nativeEffect).ToPublic());
+            }
+
+            return soundEffectInfo;
+        }
+
         /// <summary>
         /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
         /// </summary>
diff --git a/src/Tizen.Multimedia/AudioManager/SoundEffect.cs b/src/Tizen.Multimedia/AudioManager/SoundEffect.cs
new file mode 100644 (file)
index 0000000..25f6277
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Tizen.Multimedia
+{
+    /// <summary>
+    /// Specifies the sound effect types.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public enum SoundEffectType
+    {
+        /// <summary>
+        /// Noise suppression for voice call.
+        /// </summary>
+        NoiseSuppression,
+
+        /// <summary>
+        /// Auto Gain Control for normal capturing.
+        /// </summary>
+        AutoGainControl,
+
+        /// <summary>
+        /// Noise suppression + Auto Gain Control.
+        /// </summary>
+        NsWithAgc,
+
+        /// <summary>
+        /// Includes the output sound from the reference device in the recorded audio.
+        /// </summary>
+        /// <remarks>
+        /// This effect should be used with <see cref="SoundEffectInfo.ReferenceDevice"/>.
+        /// </remarks>
+        ReferenceCopy = 0x1001,
+
+        /// <summary>
+        /// AEC (Acoustic Echo Cancellation) with Speex.
+        /// </summary>
+        /// <remarks>
+        /// This effect should be used with <see cref="SoundEffectInfo.ReferenceDevice"/>.
+        /// </remarks>
+        AecSpeex,
+
+        /// <summary>
+        /// AEC (Acoustic Echo Cancellation) with WebRTC.
+        /// </summary>
+        /// <remarks>
+        /// This effect should be used with <see cref="SoundEffectInfo.ReferenceDevice"/>.
+        /// </remarks>
+        AecWebrtc
+    }
+
+    /// <summary>
+    /// Specifies the sound effect information.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public struct SoundEffectInfo
+    {
+        /// <summary>
+        /// Initializes a new instance of <see cref="SoundEffectInfo"/>.
+        /// </summary>
+        /// <param name="type">The SoundEffectType.</param>
+        /// <exception cref="ArgumentException">Invalid input enum type.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public SoundEffectInfo(SoundEffectType type)
+        {
+            ValidationUtil.ValidateEnum(typeof(SoundEffectType), type, nameof(type));
+
+            Type = type;
+            ReferenceDevice = null;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of <see cref="SoundEffectInfo"/> with a reference audio device.
+        /// </summary>
+        /// <param name="type">The SoundEffectType.</param>
+        /// <param name="device">The AudioDevice to be refered.</param>
+        /// <since_tizen> 12 </since_tizen>
+        public SoundEffectInfo(SoundEffectType type, AudioDevice device)
+        {
+            ValidationUtil.ValidateEnum(typeof(SoundEffectType), type, nameof(type));
+
+            Type = type;
+            ReferenceDevice = device;
+        }
+
+        /// <summary>
+        /// The SoundEffectType.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public SoundEffectType Type { get; }
+
+        /// <summary>
+        /// The AudioDevice used by the SoundEffect as additional source of audio data.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public AudioDevice ReferenceDevice { get; }
+    }
+
+    [Flags]
+    internal enum SoundEffectNative
+    {
+        NoiseSuppression = 1,
+        AutoGainControl = 2
+    }
+
+    internal enum SoundEffectWithReferenceNative
+    {
+        ReferenceCopy = 1,
+        AecSpeex = 2,
+        AecWebrtc = 4
+    }
+
+    internal static class EnumExtensions
+    {
+        private const string Tag = "Tizen.Multimedia.AudioManager";
+
+        internal static int ToNative(this SoundEffectType effect)
+        {
+            int ret = 0;
+
+            /* Native enum values are defined as below:
+                typedef enum {
+                    SOUND_EFFECT_REFERENCE_COPY              = 0x0001, //< Including reference source
+                    SOUND_EFFECT_ACOUSTIC_ECHO_CANCEL_SPEEX  = 0x0002, //< Acoustic echo cancel with speex
+                    SOUND_EFFECT_ACOUSTIC_ECHO_CANCEL_WEBRTC = 0x0004, //< Acoustic echo cancel with webrtc
+                } sound_effect_method_with_reference_e;
+
+                typedef enum {
+                    SOUND_EFFECT_NOISE_SUPPRESSION_VOIP          = 0x0001, //< Noise suppression for voice call
+                    SOUND_EFFECT_AUTOMATIC_GAIN_CONTROL_CAPTURE  = 0x0002, //< Auto Gain Control for normal capturing
+                } sound_effect_method_e;
+            */
+            switch (effect)
+            {
+                case SoundEffectType.NoiseSuppression:
+                    ret = 1;
+                    break;
+                case SoundEffectType.AutoGainControl:
+                    ret = 2;
+                    break;
+                case SoundEffectType.NsWithAgc:
+                    ret = 3;
+                    break;
+                case SoundEffectType.ReferenceCopy:
+                    ret = 1;
+                    break;
+                case SoundEffectType.AecSpeex:
+                    ret = 2;
+                    break;
+                case SoundEffectType.AecWebrtc:
+                    ret = 4;
+                    break;
+                default:
+                    Log.Error(Tag, "Invalid sound effect type.");
+                    break;
+            }
+
+            return ret;
+        }
+
+        internal static SoundEffectType ToPublic(this SoundEffectNative effect)
+        {
+            SoundEffectType ret = SoundEffectType.NoiseSuppression;
+
+            /* Native enum values are defined as below. And these can be set together.
+                typedef enum {
+                    SOUND_EFFECT_NOISE_SUPPRESSION_VOIP          = 0x0001, //< Noise suppression for voice call
+                    SOUND_EFFECT_AUTOMATIC_GAIN_CONTROL_CAPTURE  = 0x0002, //< Auto Gain Control for normal capturing
+                } sound_effect_method_e;
+            */
+            switch (effect)
+            {
+                case SoundEffectNative.NoiseSuppression:
+                    ret = SoundEffectType.NoiseSuppression;
+                    break;
+                case SoundEffectNative.AutoGainControl:
+                    ret = SoundEffectType.AutoGainControl;
+                    break;
+                case SoundEffectNative.NoiseSuppression | SoundEffectNative.AutoGainControl:
+                    ret = SoundEffectType.NsWithAgc;
+                    break;
+                default:
+                    Log.Error(Tag, "Invalid sound effect type.");
+                    break;
+            }
+
+            return ret;
+        }
+
+        internal static SoundEffectType ToPublic(this SoundEffectWithReferenceNative effect)
+        {
+            SoundEffectType ret = SoundEffectType.ReferenceCopy;
+
+            /* Native enum values are defined as below. And these cannot be set together.
+                typedef enum {
+                    SOUND_EFFECT_REFERENCE_COPY              = 0x0001, //< Including reference source
+                    SOUND_EFFECT_ACOUSTIC_ECHO_CANCEL_SPEEX  = 0x0002, //< Acoustic echo cancel with speex
+                    SOUND_EFFECT_ACOUSTIC_ECHO_CANCEL_WEBRTC = 0x0004, //< Acoustic echo cancel with webrtc
+                } sound_effect_method_with_reference_e;
+            */
+            switch (effect)
+            {
+                case SoundEffectWithReferenceNative.ReferenceCopy:
+                    ret = SoundEffectType.ReferenceCopy;
+                    break;
+                case SoundEffectWithReferenceNative.AecSpeex:
+                    ret = SoundEffectType.AecSpeex;
+                    break;
+                case SoundEffectWithReferenceNative.AecWebrtc:
+                    ret = SoundEffectType.AecWebrtc;
+                    break;
+                default:
+                    Log.Error(Tag, "Invalid sound effect type.");
+                    break;
+            }
+
+            return ret;
+        }
+    }
+
+}
index ede356298589963269598413511ef6b3d90053c0..1c8f91b97a9413ee9a647d46f8df8bbf8415baa4 100644 (file)
@@ -91,6 +91,20 @@ namespace Tizen.Multimedia
             [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_is_stream_on_device_by_id")]
             internal static extern AudioManagerError IsStreamOnDevice(AudioStreamPolicyHandle streamInfo, int deviceId,
                 out bool isOn);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_set_effect_method_with_reference_by_id")]
+            internal static extern AudioManagerError SetSoundEffectWithReference(AudioStreamPolicyHandle streamInfo,
+                SoundEffectWithReferenceNative effect, int deviceId);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_get_effect_method_with_reference")]
+            internal static extern AudioManagerError GetSoundEffectWithReference(AudioStreamPolicyHandle streamInfo,
+                out SoundEffectWithReferenceNative effect, out int deviceId);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_set_effect_method")]
+            internal static extern AudioManagerError SetSoundEffect(AudioStreamPolicyHandle streamInfo, int effect);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_get_effect_method")]
+            internal static extern AudioManagerError GetSoundEffect(AudioStreamPolicyHandle streamInfo, out int effect);
         }
     }
 }
\ No newline at end of file