[WebRTC] Fix bugs (#3618)
authorHaesu Gwon <haesu.gwon@samsung.com>
Wed, 29 Sep 2021 03:36:49 +0000 (12:36 +0900)
committerGitHub <noreply@github.com>
Wed, 29 Sep 2021 03:36:49 +0000 (12:36 +0900)
* [WebRTC] Fix bugs

* [WebRTC] Fix description error

src/Tizen.Multimedia.Remoting/WebRTC/MediaSource.cs
src/Tizen.Multimedia.Remoting/WebRTC/MediaStreamTrack.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.Properties.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTCDataChannel.Events.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTCDataChannel.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTCEnums.cs

index 438e296..83a808a 100755 (executable)
@@ -82,7 +82,7 @@ namespace Tizen.Multimedia.Remoting
             {
                 if (!SourceId.HasValue)
                 {
-                    throw new InvalidOperationException("MediaSource is not attached yet. Call SetSource() first.");
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
                 }
 
                 NativeWebRTC.GetTransceiverDirection(WebRtc.Handle, SourceId.Value, MediaType, out TransceiverDirection mode).
@@ -94,7 +94,7 @@ namespace Tizen.Multimedia.Remoting
             {
                 if (!SourceId.HasValue)
                 {
-                    throw new InvalidOperationException("MediaSource is not attached yet. Call SetSource() first.");
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
                 }
 
                 NativeWebRTC.SetTransceiverDirection(WebRtc.Handle, SourceId.Value, MediaType, value).
@@ -113,6 +113,11 @@ namespace Tizen.Multimedia.Remoting
         {
             get
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
+
                 NativeWebRTC.GetPause(WebRtc.Handle, SourceId.Value, MediaType, out bool isPaused).
                     ThrowIfFailed("Failed to get pause");
 
@@ -120,6 +125,11 @@ namespace Tizen.Multimedia.Remoting
             }
             set
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
+
                 NativeWebRTC.SetPause(WebRtc.Handle, SourceId.Value, MediaType, value).
                     ThrowIfFailed("Failed to set pause");
             }
@@ -136,6 +146,11 @@ namespace Tizen.Multimedia.Remoting
         {
             get
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
+
                 NativeWebRTC.GetMute(WebRtc.Handle, SourceId.Value, MediaType, out bool isMuted).
                     ThrowIfFailed("Failed to get mute");
 
@@ -143,6 +158,11 @@ namespace Tizen.Multimedia.Remoting
             }
             set
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
+
                 NativeWebRTC.SetMute(WebRtc.Handle, SourceId.Value, MediaType, value).
                     ThrowIfFailed("Failed to set mute");
             }
@@ -152,17 +172,24 @@ namespace Tizen.Multimedia.Remoting
         /// Gets or sets the video resolution of the current media source.
         /// </summary>
         /// <value>A value that specifies the mute status.</value>
-        /// <exception cref="ArgumentException">This source is not video source.</exception>
-        /// <exception cref="InvalidOperationException">MediaSource is not attached yet.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     MediaSource is not attached yet.<br/>
+        /// -or-<br/>
+        ///     This MediaSource is not Video
+        /// </exception>
         /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
         /// <since_tizen> 9 </since_tizen>
         public Size VideoResolution
         {
             get
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
                 if (MediaType != MediaType.Video)
                 {
-                    throw new ArgumentException("This property is only for video.");
+                    throw new InvalidOperationException("This property is only for video.");
                 }
 
                 NativeWebRTC.GetVideoResolution(WebRtc.Handle, SourceId.Value, out int width, out int height).
@@ -172,9 +199,13 @@ namespace Tizen.Multimedia.Remoting
             }
             set
             {
+                if (!SourceId.HasValue)
+                {
+                    throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+                }
                 if (MediaType != MediaType.Video)
                 {
-                    throw new ArgumentException("This property is only for video.");
+                    throw new InvalidOperationException("This property is only for video.");
                 }
 
                 NativeWebRTC.SetVideoResolution(WebRtc.Handle, SourceId.Value, value.Width, value.Height).
@@ -192,7 +223,11 @@ namespace Tizen.Multimedia.Remoting
         /// <see cref="AudioStreamType.MediaExternalOnly"/>.<br/>
         /// </remarks>
         /// <exception cref="ArgumentNullException"><paramref name="policy"/> is null.</exception>
-        /// <exception cref="InvalidOperationException">This MediaSource is not Audio</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     MediaSource is not attached yet.<br/>
+        /// -or-<br/>
+        ///     This MediaSource is not Audio
+        /// </exception>
         /// <exception cref="NotSupportedException">
         ///     <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported on the current platform.
         /// </exception>
@@ -202,11 +237,14 @@ namespace Tizen.Multimedia.Remoting
         /// <returns><see cref="MediaStreamTrack"/></returns>
         public MediaStreamTrack EnableAudioLoopback(AudioStreamPolicy policy)
         {
+            if (!SourceId.HasValue)
+            {
+                throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+            }
             if (policy == null)
             {
                 throw new ArgumentNullException(nameof(policy));
             }
-
             if (MediaType != MediaType.Audio)
             {
                 throw new InvalidOperationException("AudioLoopback is only for Audio MediaSource");
@@ -240,18 +278,25 @@ namespace Tizen.Multimedia.Remoting
         /// <param name="display">The <see cref="Display"/> to apply.</param>
         /// <exception cref="ArgumentException">The display has already been assigned to another.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="display"/> is null.</exception>
-        /// <exception cref="InvalidOperationException">This MediaSource is not Video</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     MediaSource is not attached yet.<br/>
+        /// -or-<br/>
+        ///     This MediaSource is not Video
+        /// </exception>
         /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
         /// <returns><see cref="MediaStreamTrack"/></returns>
         public MediaStreamTrack EnableVideoLoopback(Display display)
         {
             uint trackId = 0;
 
+            if (!SourceId.HasValue)
+            {
+                throw new InvalidOperationException("MediaSource is not attached yet. Call AddSource() first.");
+            }
             if (display == null)
             {
                 throw new ArgumentNullException(nameof(display), "Display cannot be null.");
             }
-
             if (MediaType != MediaType.Video)
             {
                 throw new InvalidOperationException("VideoLoopback is only for Video MediaSource");
index de9a226..6a4fd4c 100755 (executable)
@@ -131,6 +131,11 @@ namespace Tizen.Multimedia.Remoting
         {
             get
             {
+                if (Type != MediaType.Video)
+                {
+                    throw new InvalidOperationException("This property is only for video.");
+                }
+
                 NativeWebRTC.GetDisplayMode(_webRtc.Handle, _trackId, out var val).
                     ThrowIfFailed("Failed to get WebRTC display mode");
 
@@ -138,6 +143,11 @@ namespace Tizen.Multimedia.Remoting
             }
             set
             {
+                if (Type != MediaType.Video)
+                {
+                    throw new InvalidOperationException("This property is only for video.");
+                }
+
                 ValidationUtil.ValidateEnum(typeof(WebRTCDisplayMode), value, nameof(value));
 
                 NativeWebRTC.SetDisplayMode(_webRtc.Handle, _trackId, value).
@@ -158,6 +168,11 @@ namespace Tizen.Multimedia.Remoting
         {
             get
             {
+                if (Type != MediaType.Video)
+                {
+                    throw new InvalidOperationException("This property is only for video.");
+                }
+
                 NativeWebRTC.GetDisplayVisible(_webRtc.Handle, _trackId, out bool val).
                     ThrowIfFailed("Failed to get visible status");
 
@@ -165,6 +180,11 @@ namespace Tizen.Multimedia.Remoting
             }
             set
             {
+                if (Type != MediaType.Video)
+                {
+                    throw new InvalidOperationException("This property is only for video.");
+                }
+
                 NativeWebRTC.SetDisplayVisible(_webRtc.Handle, _trackId, value).
                     ThrowIfFailed("Failed to set display status.");
             }
index 5e7c0ce..cdb0a77 100755 (executable)
@@ -146,6 +146,7 @@ namespace Tizen.Multimedia.Remoting
         /// Gets or sets the STUN server url.
         /// </summary>
         /// <value>The STUN server url</value>
+        /// <exception cref="ArgumentNullException">STUN server URI is null.</exception>
         /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
         /// <since_tizen> 9 </since_tizen>
         public string StunServer
index b077eb3..0e6d427 100755 (executable)
@@ -108,25 +108,6 @@ namespace Tizen.Multimedia.Remoting
             if (_disposed || !disposing)
                 return;
 
-            if (_source != null && _source.Count > 0)
-            {
-                try
-                {
-                    Log.Info(WebRTCLog.Tag, "Detach sources");
-                    foreach (var source in _source)
-                    {
-                        source.ReplaceDisplay(null);
-                        source.DetachFrom(this);
-                    }
-                    _source.Clear();
-                    _source = null;
-                }
-                catch (Exception ex)
-                {
-                    Log.Error(WebRTCLog.Tag, ex.ToString());
-                }
-            }
-
             if (_handle != null)
             {
                 _handle.Dispose();
index 2c277f9..2107fdc 100755 (executable)
@@ -1,3 +1,4 @@
+using System.ComponentModel;
 /*
  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
  *
@@ -30,80 +31,173 @@ namespace Tizen.Multimedia.Remoting
         private NativeDataChannel.MessageReceivedCallback _webRtcDataChannelMsgRecvCallback;
         private NativeDataChannel.ErrorOccurredCallback _webRtcDataChannelErrorOccurredCallback;
 
+        private event EventHandler<EventArgs> _opened;
+        private event EventHandler<EventArgs> _closed;
+        private event EventHandler<WebRTCDataChannelMessageReceivedEventArgs> _messageReceived;
+        private event EventHandler<WebRTCDataChannelErrorOccurredEventArgs> _errorOccurred;
+
         /// <summary>
         /// Occurs when the data channel's underlying data transport is established.
         /// </summary>
         /// <since_tizen> 9 </since_tizen>
-        public event EventHandler<EventArgs> Opened;
+        public event EventHandler<EventArgs> Opened
+        {
+            add
+            {
+                if (_opened == null)
+                {
+                    RegisterDataChannelOpenedCallback();
+                }
+                _opened += value;
+            }
+            remove
+            {
+                _opened -= value;
+                if (_opened == null)
+                {
+                    UnregisterDataChannelOpenedCallback();
+                }
+            }
+        }
 
         /// <summary>
         /// Occurs when the data channel has closed down.
         /// </summary>
         /// <since_tizen> 9 </since_tizen>
-        public event EventHandler<EventArgs> Closed;
+        public event EventHandler<EventArgs> Closed
+        {
+            add
+            {
+                if (_closed == null)
+                {
+                    RegisterDataChannelClosedCallback();
+                }
+                _closed += value;
+            }
+            remove
+            {
+                _closed -= value;
+                if (_closed == null)
+                {
+                    UnregisterDataChannelClosedCallback();
+                }
+            }
+        }
 
         /// <summary>
         /// Occurs when a message is received from the remote peer.
         /// </summary>
         /// <since_tizen> 9 </since_tizen>
-        public event EventHandler<WebRTCDataChannelMessageReceivedEventArgs> MessageReceived;
+        public event EventHandler<WebRTCDataChannelMessageReceivedEventArgs> MessageReceived
+        {
+            add
+            {
+                if (_messageReceived == null)
+                {
+                    RegisterDataChannelMessageReceivedCallback();
+                }
+                _messageReceived += value;
+            }
+            remove
+            {
+                _messageReceived -= value;
+                if (_messageReceived == null)
+                {
+                    UnregisterDataChannelMessageReceivedCallback();
+                }
+            }
+        }
 
         /// <summary>
         /// Occurs when an error occurs on the data channel.
         /// </summary>
         /// <since_tizen> 9 </since_tizen>
-        public event EventHandler<WebRTCDataChannelErrorOccurredEventArgs> ErrorOccurred;
-
-        private void RegisterEvents()
+        public event EventHandler<WebRTCDataChannelErrorOccurredEventArgs> ErrorOccurred
         {
-            RegisterDataChannelOpenedCallback();
-            RegisterDataChannelClosedCallback();
-            RegisterDataChannelMsgRecvCallback();
-            RegisterDataChannelErrorOccurredCallback();
+            add
+            {
+                if (_errorOccurred == null)
+                {
+                    RegisterDataChannelErrorOccurredCallback();
+                }
+                _errorOccurred += value;
+            }
+            remove
+            {
+                _errorOccurred -= value;
+                if (_errorOccurred == null)
+                {
+                    UnregisterDataChannelErrorOccurredCallback();
+                }
+            }
         }
 
         private void RegisterDataChannelOpenedCallback()
         {
             _webRtcDataChannelOpenedCallback = (dataChannelHandle, _) =>
             {
-                Opened?.Invoke(this, new EventArgs());
+                _opened?.Invoke(this, new EventArgs());
             };
 
             NativeDataChannel.SetOpenedCb(_handle, _webRtcDataChannelOpenedCallback).
                 ThrowIfFailed("Failed to set data channel opened callback.");
         }
 
-        private void RegisterDataChannelMsgRecvCallback()
+        private void UnregisterDataChannelOpenedCallback()
+        {
+            NativeDataChannel.UnsetOpenedCb(_handle).
+                ThrowIfFailed("Failed to unset data channel opened callback.");
+        }
+
+        private void RegisterDataChannelClosedCallback()
+        {
+            _webRtcDataChannelClosedCallback = (dataChannelHandle, _) =>
+            {
+                _closed?.Invoke(this, new EventArgs());
+            };
+
+            NativeDataChannel.SetClosedCb(_handle, _webRtcDataChannelClosedCallback).
+                ThrowIfFailed("Failed to set data channel closed callback.");
+        }
+
+        private void UnregisterDataChannelClosedCallback()
+        {
+            NativeDataChannel.UnsetClosedCb(_handle).
+                ThrowIfFailed("Failed to unset data channel closed callback.");
+        }
+
+        private void RegisterDataChannelMessageReceivedCallback()
         {
             _webRtcDataChannelMsgRecvCallback = (dataChannelHandle, type, message, _) =>
             {
-                MessageReceived?.Invoke(this, new WebRTCDataChannelMessageReceivedEventArgs(type, message));
+                _messageReceived?.Invoke(this, new WebRTCDataChannelMessageReceivedEventArgs(type, message));
             };
 
             NativeDataChannel.SetMessageReceivedCb(_handle, _webRtcDataChannelMsgRecvCallback).
                 ThrowIfFailed("Failed to set data channel message received callback.");
         }
 
+        private void UnregisterDataChannelMessageReceivedCallback()
+        {
+            NativeDataChannel.UnsetMessageReceivedCb(_handle).
+                ThrowIfFailed("Failed to unset data channel message received callback.");
+        }
+
         private void RegisterDataChannelErrorOccurredCallback()
         {
             _webRtcDataChannelErrorOccurredCallback = (dataChannelHandle, error, _) =>
             {
-                ErrorOccurred?.Invoke(this, new WebRTCDataChannelErrorOccurredEventArgs((WebRTCError)error));
+                _errorOccurred?.Invoke(this, new WebRTCDataChannelErrorOccurredEventArgs((WebRTCError)error));
             };
 
             NativeDataChannel.SetErrorOccurredCb(_handle, _webRtcDataChannelErrorOccurredCallback).
                 ThrowIfFailed("Failed to set data channel error callback.");
         }
 
-        private void RegisterDataChannelClosedCallback()
+        private void UnregisterDataChannelErrorOccurredCallback()
         {
-            _webRtcDataChannelClosedCallback = (dataChannelHandle, _) =>
-            {
-                Closed?.Invoke(this, new EventArgs());
-            };
-
-            NativeDataChannel.SetClosedCb(_handle, _webRtcDataChannelClosedCallback).
-                ThrowIfFailed("Failed to set data channel closed callback.");
+            NativeDataChannel.UnsetErrorOccurredCb(_handle).
+                ThrowIfFailed("Failed to unset data channel error callback.");
         }
     }
 }
\ No newline at end of file
index df8eb66..327a4df 100755 (executable)
@@ -79,8 +79,6 @@ namespace Tizen.Multimedia.Remoting
             Debug.Assert(_handle != null);
 
             Label = label;
-
-            RegisterEvents();
         }
 
         internal WebRTCDataChannel(IntPtr dataChannelHandle)
@@ -97,9 +95,6 @@ namespace Tizen.Multimedia.Remoting
                 ThrowIfFailed("Failed to get label");
 
             Label = label;
-
-            Log.Info(WebRTCLog.Tag, "Register event");
-            RegisterEvents();
         }
 
         private IntPtr Handle
@@ -179,7 +174,7 @@ namespace Tizen.Multimedia.Remoting
                 return;
             }
 
-            if (true)
+            if (_handle != null)
             {
                 NativeDataChannel.Destroy(_handle);
                 _disposed = true;
index d5f6508..31d6f4b 100755 (executable)
@@ -104,7 +104,7 @@ namespace Tizen.Multimedia.Remoting
     /// <remarks>This state is related in SDP offer/answer.</remarks>
     /// <seealso cref="WebRTC.SetLocalDescription"/>
     /// <seealso cref="WebRTC.SetRemoteDescription"/>
-    /// <seealso cref="WebRTC.CreateAnswer()"/>
+    /// <seealso cref="WebRTC.CreateAnswerAsync()"/>
     /// <since_tizen> 9 </since_tizen>
     public enum WebRTCSignalingState
     {