[AudioManager] Add new class for audio ducking (#979)
authorJeongmo Yang <jm80.yang@outlook.com>
Thu, 5 Sep 2019 02:24:31 +0000 (11:24 +0900)
committerSeungbaeShin <32276666+SeungbaeShin@users.noreply.github.com>
Thu, 5 Sep 2019 02:24:31 +0000 (11:24 +0900)
* [AudioManager] Add new class for audio ducking

- Added class
 : AudioDucking
 : AudioDuckingStateChangedEventArgs
 : AudioDuckingHandle

Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
src/Tizen.Multimedia/AudioManager/AudioDucking.cs [new file with mode: 0644]
src/Tizen.Multimedia/AudioManager/AudioDuckingStateChangedEventArgs.cs [new file with mode: 0644]
src/Tizen.Multimedia/Interop/AudioDuckingHandle.cs [new file with mode: 0644]
src/Tizen.Multimedia/Interop/Interop.Ducking.cs [new file with mode: 0644]

diff --git a/src/Tizen.Multimedia/AudioManager/AudioDucking.cs b/src/Tizen.Multimedia/AudioManager/AudioDucking.cs
new file mode 100644 (file)
index 0000000..c980084
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2019 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;
+using System.Diagnostics;
+
+namespace Tizen.Multimedia
+{
+    /// <summary>
+    /// Provides the ability to control audio ducking.
+    /// </summary>
+    /// <seealso cref="AudioManager"/>
+    /// <since_tizen> 6 </since_tizen>
+    public sealed class AudioDucking : IDisposable
+    {
+        private AudioDuckingHandle _handle;
+        private bool _disposed = false;
+        private Interop.AudioDucking.DuckingStateChangedCallback _duckingStateChangedCallback;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AudioDucking"/> class with <see cref="AudioStreamType"/>.
+        /// </summary>
+        /// <param name="targetType">The type of sound stream to be affected by this new instance.</param>
+        /// <exception cref="ArgumentException"><paramref name="targetType"/> is invalid.</exception>
+        /// <exception cref="InvalidOperationException">Operation failed; internal error.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public AudioDucking(AudioStreamType targetType)
+        {
+            ValidationUtil.ValidateEnum(typeof(AudioStreamType), targetType, nameof(targetType));
+
+            _duckingStateChangedCallback = (AudioDuckingHandle ducking, bool isDucked, IntPtr _) =>
+            {
+                DuckingStateChanged?.Invoke(this,
+                    new AudioDuckingStateChangedEventArgs(IsDucked));
+            };
+
+            Interop.AudioDucking.Create(targetType, _duckingStateChangedCallback,
+                IntPtr.Zero, out _handle).ThrowIfError("Unable to create stream ducking");
+
+            Debug.Assert(_handle != null);
+        }
+
+        /// <summary>
+        /// Occurs when the ducking state is changed.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public event EventHandler<AudioDuckingStateChangedEventArgs> DuckingStateChanged;
+
+        /// <summary>
+        /// Gets the ducking state of the stream.
+        /// </summary>
+        /// <value>true if the audio stream is ducked; otherwise, false.</value>
+        /// <exception cref="InvalidOperationException">Operation failed; internal error.</exception>
+        /// <exception cref="ObjectDisposedException">The <see cref="AudioDucking"/> has already been disposed of.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public bool IsDucked
+        {
+            get
+            {
+                if (_disposed)
+                {
+                    throw new ObjectDisposedException(nameof(AudioDucking));
+                }
+
+                Interop.AudioDucking.IsDucked(Handle, out bool isDucked).
+                    ThrowIfError("Failed to get the running state of the device");
+
+                return isDucked;
+            }
+        }
+
+        /// <summary>
+        /// Activate audio ducking
+        /// </summary>
+        /// <param name="duration">The duration(milisecond) for ducking.</param>
+        /// <param name="ratio">The volume ratio when ducked.</param>
+        /// <remarks>To activate ducking, the specified privilege is required.</remarks>
+        /// <privilege>http://tizen.org/privilege/volume.set</privilege>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///     <paramref name="duration"/> is less than 0 or greater than 3000.<br/>
+        ///     -or-<br/>
+        ///     <paramref name="ratio"/> is less than 0.0 or greater than or equal to 1.0.<br/>
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.<br/>
+        ///     -or-<br/>
+        ///     The target stream is already ducked.
+        /// </exception>
+        /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege to set volume.</exception>
+        /// <exception cref="ObjectDisposedException">The <see cref="AudioDucking"/> has already been disposed of.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public void Activate(uint duration, double ratio)
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(nameof(AudioDucking));
+            }
+
+            if (duration < 0 || duration > 3000)
+            {
+                throw new ArgumentOutOfRangeException(nameof(duration), duration, "Valid range : 0 <= duration <= 3000");
+            }
+
+            if (ratio < 0.0 || ratio >= 1.0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(ratio), ratio, "Valid range : 0 <= ratio < 1.0");
+            }
+
+            Interop.AudioDucking.Activate(Handle, duration, ratio).
+                ThrowIfError("Failed to activate ducking");
+        }
+
+        /// <summary>
+        /// Deactivate audio ducking
+        /// </summary>
+        /// <remarks>To deactivate ducking, the specified privilege is required.</remarks>
+        /// <privilege>http://tizen.org/privilege/volume.set</privilege>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.<br/>
+        ///     -or-<br/>
+        ///     The target stream is already unducked.
+        /// </exception>
+        /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege to set volume.</exception>
+        /// <exception cref="ObjectDisposedException">The <see cref="AudioDucking"/> has already been disposed of.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public void Deactivate()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(nameof(AudioDucking));
+            }
+
+            Interop.AudioDucking.Deactivate(Handle).
+                ThrowIfError("Failed to deactivate ducking");
+        }
+
+        /// <summary>
+        /// Releases all resources used by the <see cref="AudioDucking"/>.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public void Dispose()
+        {
+            if (_disposed)
+            {
+                return;
+            }
+
+            if (_handle != null)
+            {
+                _handle.Dispose();
+            }
+
+            _disposed = true;
+            GC.SuppressFinalize(this);
+        }
+
+        internal AudioDuckingHandle Handle
+        {
+            get
+            {
+                if (_disposed)
+                {
+                    throw new ObjectDisposedException(nameof(AudioDucking));
+                }
+                return _handle;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia/AudioManager/AudioDuckingStateChangedEventArgs.cs b/src/Tizen.Multimedia/AudioManager/AudioDuckingStateChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..9c31bb8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 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>
+    /// Provides data for the <see cref="AudioDucking.DuckingStateChanged"/> event.
+    /// </summary>
+    /// <since_tizen> 6 </since_tizen>
+    public class AudioDuckingStateChangedEventArgs : EventArgs
+    {
+        internal AudioDuckingStateChangedEventArgs(bool isDucked)
+        {
+            IsDucked = isDucked;
+        }
+
+        /// <summary>
+        /// Gets the ducking state of the stream.
+        /// </summary>
+        /// <value>true if the state is ducked; otherwise, false.</value>
+        /// <since_tizen> 6 </since_tizen>
+        public bool IsDucked { get; }
+    }
+}
diff --git a/src/Tizen.Multimedia/Interop/AudioDuckingHandle.cs b/src/Tizen.Multimedia/Interop/AudioDuckingHandle.cs
new file mode 100644 (file)
index 0000000..69500b4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 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;
+using System.Runtime.InteropServices;
+
+namespace Tizen.Multimedia
+{
+    internal class AudioDuckingHandle : SafeHandle
+    {
+        protected AudioDuckingHandle() : base(IntPtr.Zero, true)
+        {
+        }
+
+        public override bool IsInvalid => handle == IntPtr.Zero;
+
+        protected override bool ReleaseHandle()
+        {
+            var ret = Interop.AudioDucking.Destroy(handle);
+            if (ret != AudioManagerError.None)
+            {
+                Log.Debug(GetType().FullName, $"Failed to release native {GetType()}");
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia/Interop/Interop.Ducking.cs b/src/Tizen.Multimedia/Interop/Interop.Ducking.cs
new file mode 100644 (file)
index 0000000..7cdc824
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 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;
+using System.Runtime.InteropServices;
+
+namespace Tizen.Multimedia
+{
+    internal static partial class Interop
+    {
+        internal static partial class AudioDucking
+        {
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+            internal delegate void DuckingStateChangedCallback(AudioDuckingHandle ducking, bool isDucked, IntPtr userData);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_create_stream_ducking")]
+            internal static extern AudioManagerError Create(AudioStreamType targetType,
+                DuckingStateChangedCallback callback, IntPtr userData, out AudioDuckingHandle ducking);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_destroy_stream_ducking")]
+            internal static extern AudioManagerError Destroy(IntPtr ducking);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_is_ducked")]
+            internal static extern AudioManagerError IsDucked(AudioDuckingHandle ducking, out bool isDucked);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_activate_ducking")]
+            internal static extern AudioManagerError Activate(AudioDuckingHandle ducking, uint duration, double ratio);
+
+            [DllImport(Libraries.SoundManager, EntryPoint = "sound_manager_deactivate_ducking")]
+            internal static extern AudioManagerError Deactivate(AudioDuckingHandle ducking);
+        }
+    }
+}
\ No newline at end of file