diff --git a/Plugin~/WebRTCPlugin/Context.cpp b/Plugin~/WebRTCPlugin/Context.cpp index efc6f4288..94ab40346 100644 --- a/Plugin~/WebRTCPlugin/Context.cpp +++ b/Plugin~/WebRTCPlugin/Context.cpp @@ -241,14 +241,9 @@ namespace webrtc // todo:(kazuki) } - rtc::scoped_refptr Context::CreateAudioSource() + rtc::scoped_refptr Context::CreateAudioSource(const cricket::AudioOptions& options) { - // avoid optimization specially for voice - cricket::AudioOptions audioOptions; - audioOptions.auto_gain_control = false; - audioOptions.noise_suppression = false; - audioOptions.highpass_filter = false; - return UnityAudioTrackSource::Create(audioOptions); + return UnityAudioTrackSource::Create(options); } rtc::scoped_refptr diff --git a/Plugin~/WebRTCPlugin/Context.h b/Plugin~/WebRTCPlugin/Context.h index 3de558ef1..94088e3bd 100644 --- a/Plugin~/WebRTCPlugin/Context.h +++ b/Plugin~/WebRTCPlugin/Context.h @@ -103,7 +103,7 @@ namespace webrtc MediaStreamObserver* GetObserver(const webrtc::MediaStreamInterface* stream); // Audio Source - rtc::scoped_refptr CreateAudioSource(); + rtc::scoped_refptr CreateAudioSource(const cricket::AudioOptions& options); // Audio Renderer AudioTrackSinkAdapter* CreateAudioTrackSinkAdapter(); void DeleteAudioTrackSinkAdapter(AudioTrackSinkAdapter* sink); diff --git a/Plugin~/WebRTCPlugin/WebRTCPlugin.cpp b/Plugin~/WebRTCPlugin/WebRTCPlugin.cpp index aeaf6a316..d59fedf02 100644 --- a/Plugin~/WebRTCPlugin/WebRTCPlugin.cpp +++ b/Plugin~/WebRTCPlugin/WebRTCPlugin.cpp @@ -288,9 +288,35 @@ extern "C" return source.get(); } - UNITY_INTERFACE_EXPORT webrtc::AudioSourceInterface* ContextCreateAudioTrackSource(Context* context) + struct AudioOptions { - rtc::scoped_refptr source = context->CreateAudioSource(); + Optional echoCancellation; + Optional autoGainControl; + Optional noiseSuppression; + Optional highpassFilter; + + operator cricket::AudioOptions() const + { + cricket::AudioOptions dst = {}; + dst.echo_cancellation = static_cast>(echoCancellation); + dst.auto_gain_control = static_cast>(autoGainControl); + dst.noise_suppression = static_cast>(noiseSuppression); + dst.highpass_filter = static_cast>(highpassFilter); +#if defined(WEBRTC_IOS) + if (dst.echo_cancellation && dst.echo_cancellation.value()) + { + dst.ios_force_software_aec_HACK = true; + } +#endif + return dst; + } + }; + + UNITY_INTERFACE_EXPORT webrtc::AudioSourceInterface* + ContextCreateAudioTrackSource(Context* context, const AudioOptions* options) + { + cricket::AudioOptions _options = *options; + rtc::scoped_refptr source = context->CreateAudioSource(_options); context->AddRefPtr(source); return source.get(); } diff --git a/Plugin~/WebRTCPluginTest/ContextTest.cpp b/Plugin~/WebRTCPluginTest/ContextTest.cpp index 4b995c703..e4cd9b2ad 100644 --- a/Plugin~/WebRTCPluginTest/ContextTest.cpp +++ b/Plugin~/WebRTCPluginTest/ContextTest.cpp @@ -85,7 +85,7 @@ namespace webrtc TEST_P(ContextTest, CreateAndDeleteAudioTrack) { - const auto source = context->CreateAudioSource(); + const auto source = context->CreateAudioSource(cricket::AudioOptions()); EXPECT_NE(nullptr, source); const auto track = context->CreateAudioTrack("audio", source.get()); EXPECT_NE(nullptr, track); @@ -95,7 +95,7 @@ namespace webrtc { const auto stream = context->CreateMediaStream("audiostream"); EXPECT_NE(nullptr, stream); - const auto source = context->CreateAudioSource(); + const auto source = context->CreateAudioSource(cricket::AudioOptions()); EXPECT_NE(nullptr, source); const auto track = context->CreateAudioTrack("audio", source.get()); EXPECT_NE(nullptr, track); diff --git a/Runtime/Scripts/AudioStreamTrack.cs b/Runtime/Scripts/AudioStreamTrack.cs index 1afd0cf72..95c81dba4 100644 --- a/Runtime/Scripts/AudioStreamTrack.cs +++ b/Runtime/Scripts/AudioStreamTrack.cs @@ -29,6 +29,32 @@ public static void SetTrack(this AudioSource source, AudioStreamTrack track) } } + /// + /// + /// + public class AudioOptions + { + /// + /// + /// + public bool? echoCancellation; + /// + /// + /// + public bool? autoGainControl; + + /// + /// + /// + public bool? noiseSuppression; + + /// + /// + /// + public bool? highpassFilter; + + } + /// /// /// @@ -184,8 +210,8 @@ internal void SetData(float[] data, int channels, int sampleRate) /// /// /// - public AudioStreamTrack() - : this(Guid.NewGuid().ToString(), new AudioTrackSource()) + public AudioStreamTrack(AudioOptions options = null) + : this(Guid.NewGuid().ToString(), new AudioTrackSource(options)) { } @@ -193,8 +219,8 @@ public AudioStreamTrack() /// /// /// - public AudioStreamTrack(AudioSource source) - : this(Guid.NewGuid().ToString(), new AudioTrackSource()) + public AudioStreamTrack(AudioSource source, AudioOptions options = null) + : this(Guid.NewGuid().ToString(), new AudioTrackSource(options)) { if (source == null) throw new ArgumentNullException("source", "AudioSource argument is null."); @@ -206,8 +232,8 @@ public AudioStreamTrack(AudioSource source) _audioCapturer.sender = true; } - public AudioStreamTrack(AudioListener listener) - : this(Guid.NewGuid().ToString(), new AudioTrackSource()) + public AudioStreamTrack(AudioListener listener, AudioOptions options = null) + : this(Guid.NewGuid().ToString(), new AudioTrackSource(options)) { if (listener == null) throw new ArgumentNullException("listener", "AudioListener argument is null."); @@ -369,13 +395,40 @@ public event AudioReadEventHandler onReceived } } + [StructLayout(LayoutKind.Sequential)] + internal struct AudioOptionsInternal + { + public OptionalBool echoCancellation; + public OptionalBool autoGainControl; + public OptionalBool noiseSuppression; + public OptionalBool highpassFilter; + + public static explicit operator AudioOptionsInternal(AudioOptions origin) + { + AudioOptionsInternal dst = new AudioOptionsInternal + { + echoCancellation = origin.echoCancellation, + autoGainControl = origin.autoGainControl, + noiseSuppression = origin.noiseSuppression, + highpassFilter = origin.highpassFilter + }; + return dst; + } + } + internal class AudioTrackSource : RefCountedObject { - public AudioTrackSource() : base(WebRTC.Context.CreateAudioTrackSource()) + public AudioTrackSource(AudioOptions options = null) : base(CreateAudioTrackSource(options)) { WebRTC.Table.Add(self, this); } + static IntPtr CreateAudioTrackSource(AudioOptions options) + { + var _options = options == null ? new AudioOptionsInternal() : (AudioOptionsInternal)options; + return WebRTC.Context.CreateAudioTrackSource(ref _options); + } + ~AudioTrackSource() { this.Dispose(); diff --git a/Runtime/Scripts/Context.cs b/Runtime/Scripts/Context.cs index 55c5ca637..83f540577 100644 --- a/Runtime/Scripts/Context.cs +++ b/Runtime/Scripts/Context.cs @@ -325,9 +325,9 @@ public IntPtr CreateVideoTrackSource() return NativeMethods.ContextCreateVideoTrackSource(self); } - public IntPtr CreateAudioTrackSource() + public IntPtr CreateAudioTrackSource(ref AudioOptionsInternal options) { - return NativeMethods.ContextCreateAudioTrackSource(self); + return NativeMethods.ContextCreateAudioTrackSource(self, ref options); } public IntPtr CreateAudioTrack(string label, IntPtr trackSource) diff --git a/Runtime/Scripts/WebRTC.cs b/Runtime/Scripts/WebRTC.cs index b5228adad..91fc4a55f 100644 --- a/Runtime/Scripts/WebRTC.cs +++ b/Runtime/Scripts/WebRTC.cs @@ -1277,7 +1277,7 @@ public static extern void RegisterDebugLog(DelegateDebugLog func, [MarshalAs(Unm [DllImport(WebRTC.Lib)] public static extern void ContextDeleteDataChannel(IntPtr ptr, IntPtr ptrChannel); [DllImport(WebRTC.Lib)] - public static extern IntPtr ContextCreateAudioTrackSource(IntPtr ptr); + public static extern IntPtr ContextCreateAudioTrackSource(IntPtr ptr, ref AudioOptionsInternal options); [DllImport(WebRTC.Lib)] public static extern IntPtr ContextCreateVideoTrackSource(IntPtr ptr); [DllImport(WebRTC.Lib)] diff --git a/Tests/Runtime/ContextTest.cs b/Tests/Runtime/ContextTest.cs index 2cf9710ae..1e7451605 100644 --- a/Tests/Runtime/ContextTest.cs +++ b/Tests/Runtime/ContextTest.cs @@ -80,7 +80,8 @@ public void CreateAndDeleteDataChannel() public void CreateAndDeleteAudioTrack() { var context = WebRTC.Context; - var source = context.CreateAudioTrackSource(); + var options = new AudioOptionsInternal(); + var source = context.CreateAudioTrackSource(ref options); var track = context.CreateAudioTrack("audio", source); context.DeleteRefPtr(track); context.DeleteRefPtr(source); diff --git a/Tests/Runtime/NativeAPITest.cs b/Tests/Runtime/NativeAPITest.cs index 3b49ff7cd..f6ce6d9bf 100644 --- a/Tests/Runtime/NativeAPITest.cs +++ b/Tests/Runtime/NativeAPITest.cs @@ -229,7 +229,8 @@ public void AddAndRemoveVideoTrackToMediaStream() public void AddAndRemoveAudioTrackToMediaStream() { var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream"); - var source = NativeMethods.ContextCreateAudioTrackSource(context); + var options = new AudioOptionsInternal(); + var source = NativeMethods.ContextCreateAudioTrackSource(context, ref options); var track = NativeMethods.ContextCreateAudioTrack(context, "audio", source); NativeMethods.MediaStreamAddTrack(stream, track); @@ -262,7 +263,8 @@ public void AddAndRemoveAudioTrack() var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream"); var streamId = NativeMethods.MediaStreamGetID(stream).AsAnsiStringWithFreeMem(); Assert.IsNotEmpty(streamId); - var source = NativeMethods.ContextCreateAudioTrackSource(context); + var options = new AudioOptionsInternal(); + var source = NativeMethods.ContextCreateAudioTrackSource(context, ref options); var track = NativeMethods.ContextCreateAudioTrack(context, "audio", source); var error = NativeMethods.PeerConnectionAddTrack(peer, track, streamId, out var sender); Assert.That(error, Is.EqualTo(RTCErrorType.None));