Skip to content

Commit

Permalink
[AudioManager] Add new SoundEffect APIs (Samsung#6329)
Browse files Browse the repository at this point in the history
  • Loading branch information
hsgwon authored and bshsqa committed Sep 25, 2024
1 parent d23cf26 commit 2bef3c0
Show file tree
Hide file tree
Showing 3 changed files with 350 additions and 0 deletions.
100 changes: 100 additions & 0 deletions src/Tizen.Multimedia/AudioManager/AudioStreamPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
*/

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Tizen.Multimedia
{
Expand Down Expand Up @@ -421,6 +423,104 @@ public bool HasStreamOnDevice(AudioDevice device)
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>
Expand Down
236 changes: 236 additions & 0 deletions src/Tizen.Multimedia/AudioManager/SoundEffect.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}

}
14 changes: 14 additions & 0 deletions src/Tizen.Multimedia/Interop/Interop.StreamPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ internal static extern AudioManagerError AddFocusStateWatchCallback(AudioStreamF
[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);
}
}
}

0 comments on commit 2bef3c0

Please sign in to comment.