[WebRTC] Add new APIs for statistics (#4508)
authorHaesu Gwon <haesu.gwon@samsung.com>
Wed, 7 Sep 2022 07:20:34 +0000 (16:20 +0900)
committerGitHub <noreply@github.com>
Wed, 7 Sep 2022 07:20:34 +0000 (16:20 +0900)
* [WebRTC] Add new APIs for statistics

src/Tizen.Multimedia.Remoting/Interop/Interop.WebRTC.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs
src/Tizen.Multimedia.Remoting/WebRTC/WebRTCEnums.cs

index fdd6022..2a7c310 100755 (executable)
@@ -18,6 +18,7 @@ using System;
 using System.Runtime.InteropServices;
 using Tizen;
 using Tizen.Applications;
+using Tizen.Internals;
 using Tizen.Multimedia;
 using Tizen.Multimedia.Remoting;
 
@@ -70,6 +71,9 @@ internal static partial class Interop
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate void SdpCreatedCallback(IntPtr handle, string sdp, IntPtr userData);
 
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate bool RetrieveStatsCallback(WebRTCStatisticsCategory category, IntPtr prop, IntPtr userData);
+
 
         [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_create")]
         internal static extern WebRTCErrorCode Create(out WebRTCHandle handle);
@@ -243,6 +247,9 @@ internal static partial class Interop
         [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_foreach_media_source_supported_format")]
         internal static extern WebRTCErrorCode SupportedMediaSourceFormat(IntPtr handle, SupportedMediaFormatCallback callback, IntPtr userData);
 
+        [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_foreach_stats")]
+        internal static extern WebRTCErrorCode ForeachStats(IntPtr handle, int typeMask, RetrieveStatsCallback callback, IntPtr userData = default);
+
 
         [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_error_cb")]
         internal static extern WebRTCErrorCode SetErrorOccurredCb(IntPtr handle, ErrorOccurredCallback callback, IntPtr userData = default);
@@ -315,6 +322,37 @@ internal static partial class Interop
 
         [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_encoded_video_frame_cb")]
         internal static extern WebRTCErrorCode UnsetVideoFrameEncodedCb(IntPtr handle);
+
+        [StructLayout(LayoutKind.Explicit)]
+        internal struct StatsPropertyValueStruct
+        {
+            [FieldOffsetAttribute(0)]
+            internal bool @bool;
+            [FieldOffsetAttribute(0)]
+            internal int @int;
+            [FieldOffsetAttribute(0)]
+            internal uint @uint;
+            [FieldOffsetAttribute(0)]
+            internal long @long;
+            [FieldOffsetAttribute(0)]
+            internal ulong @ulong;
+            [FieldOffsetAttribute(0)]
+            internal float @float;
+            [FieldOffsetAttribute(0)]
+            internal double @double;
+            [FieldOffsetAttribute(0)]
+            internal IntPtr @string;
+        }
+
+        [NativeStruct("webrtc_stats_prop_info_s", Include="webrtc.h", PkgConfig="capi-media-webrtc")]
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct StatsPropertyStruct
+        {
+            internal string name;
+            internal WebRTCStatisticsProperty property;
+            internal WebRTCStatsPropertyType propertyType;
+            internal StatsPropertyValueStruct value;
+        }
     }
 
     internal class WebRTCHandle : SafeHandle
index f646b6b..dd6ecff 100755 (executable)
@@ -19,6 +19,7 @@ using System.Collections.ObjectModel;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Diagnostics;
+using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
 using Tizen.Applications;
@@ -569,7 +570,7 @@ namespace Tizen.Multimedia.Remoting
         }
 
         /// <summary>
-        /// Gets all turn servers.
+        /// Retrieves all turn servers.
         /// </summary>
         /// <returns>The turn server list.</returns>
         /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
@@ -580,7 +581,7 @@ namespace Tizen.Multimedia.Remoting
 
             var list = new List<string>();
 
-            NativeWebRTC.RetrieveTurnServerCallback callback = (server, _) =>
+            NativeWebRTC.RetrieveTurnServerCallback cb = (server, _) =>
             {
                 if (!string.IsNullOrWhiteSpace(server))
                 {
@@ -590,9 +591,136 @@ namespace Tizen.Multimedia.Remoting
                 return true;
             };
 
-            NativeWebRTC.ForeachTurnServer(Handle, callback).ThrowIfFailed("Failed to retrieve turn server");
+            NativeWebRTC.ForeachTurnServer(Handle, cb).ThrowIfFailed("Failed to retrieve turn server");
 
             return list.AsReadOnly();
         }
+
+        /// <summary>
+        /// Retrieves the current statistics information.
+        /// </summary>
+        /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Playing"/></remarks>
+        /// <returns>The WebRTC statistics informations.</returns>
+        /// <param name="category">The category of statistics to get.</param>
+        /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+        /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+        /// <since_tizen> 10 </since_tizen>
+        public ReadOnlyCollection<WebRTCStatistics> GetStatistics(WebRTCStatisticsCategory category)
+        {
+            ValidateWebRTCState(WebRTCState.Playing);
+
+            var stats = new List<WebRTCStatistics>();
+            Exception caught = null;
+
+            NativeWebRTC.RetrieveStatsCallback cb = (category_, prop, _) =>
+            {
+                try
+                {
+                    stats.Add(new WebRTCStatistics(category_, prop));
+                }
+                catch (Exception e)
+                {
+                    caught = e;
+                    return false;
+                }
+
+                return true;
+            };
+
+            using (var cbKeeper = ObjectKeeper.Get(cb))
+            {
+                NativeWebRTC.ForeachStats(Handle, (int)category, cb, IntPtr.Zero).
+                    ThrowIfFailed("failed to retrieve stats");
+
+                if (caught != null)
+                {
+                    throw caught;
+                }
+            }
+
+            return new ReadOnlyCollection<WebRTCStatistics>(stats);
+        }
+
+        /// <summary>
+        /// Represents WebRTC statistics information.
+        /// </summary>
+        /// <since_tizen> 10 </since_tizen>
+        public class WebRTCStatistics
+        {
+            internal WebRTCStatistics(WebRTCStatisticsCategory type, IntPtr prop)
+            {
+                var unmanagedStruct = Marshal.PtrToStructure<NativeWebRTC.StatsPropertyStruct>(prop);
+
+                Category = type;
+                Name = unmanagedStruct.name;
+                Property = unmanagedStruct.property;
+
+                switch (unmanagedStruct.propertyType)
+                {
+                    case WebRTCStatsPropertyType.TypeBool:
+                        Value = unmanagedStruct.value.@bool;
+                        break;
+                    case WebRTCStatsPropertyType.TypeInt:
+                        Value = unmanagedStruct.value.@int;
+                        break;
+                    case WebRTCStatsPropertyType.TypeUint:
+                        Value = unmanagedStruct.value.@uint;
+                        break;
+                    case WebRTCStatsPropertyType.TypeInt64:
+                        Value = unmanagedStruct.value.@long;
+                        break;
+                    case WebRTCStatsPropertyType.TypeUint64:
+                        Value = unmanagedStruct.value.@ulong;
+                        break;
+                    case WebRTCStatsPropertyType.TypeFloat:
+                        Value = unmanagedStruct.value.@float;
+                        break;
+                    case WebRTCStatsPropertyType.TypeDouble:
+                        Value = unmanagedStruct.value.@double;
+                        break;
+                    case WebRTCStatsPropertyType.TypeString:
+                        Value = Marshal.PtrToStringAnsi(unmanagedStruct.value.@string);
+                        break;
+                    default:
+                        throw new InvalidOperationException($"No matching type [{unmanagedStruct.propertyType}]");
+                }
+            }
+
+            /// <summary>
+            /// Gets the category of statistics.
+            /// </summary>
+            /// <value>The category of WebRTC statistics information</value>
+            /// <since_tizen> 10 </since_tizen>
+            public WebRTCStatisticsCategory Category { get; }
+
+            /// <summary>
+            /// Gets the name of statistics.
+            /// </summary>
+            /// <value>The name of WebRTC statistics information</value>
+            /// <since_tizen> 10 </since_tizen>
+            public string Name { get; }
+
+            /// <summary>
+            /// Gets the property of statistics.
+            /// </summary>
+            /// <value>The property of WebRTC statistics information</value>
+            /// <since_tizen> 10 </since_tizen>
+            public WebRTCStatisticsProperty Property { get; }
+
+            /// <summary>
+            /// Gets the value of statistics.
+            /// </summary>
+            /// <value>The value of WebRTC statistics information</value>
+            /// <since_tizen> 10 </since_tizen>
+            public object Value { get; }
+
+            /// <summary>
+            /// Returns a string that represents the current object.
+            /// </summary>
+            /// <returns>A string that represents the current object.</returns>
+            /// <since_tizen> 10 </since_tizen>
+            public override string ToString() =>
+                $"Category={Category}, Name={Name}, Property={Property}, Value={Value}, Type={Value.GetType()}";
+        }
     }
-}
\ No newline at end of file
+}
index a20d092..8402c8c 100755 (executable)
@@ -476,4 +476,218 @@ namespace Tizen.Multimedia.Remoting
 
         Evas,
     }
-}
\ No newline at end of file
+
+    /// <summary>
+    /// Specifies the category of WebRTC statistics.
+    /// </summary>
+    /// <since_tizen> 10 </since_tizen>
+    [Flags]
+    public enum WebRTCStatisticsCategory
+    {
+        /// <summary>
+        /// Codec.
+        /// </summary>
+        Codec = 0x0001,
+
+        /// <summary>
+        /// Inbound RTP.
+        /// </summary>
+        InboundRtp = 0x0002,
+
+        /// <summary>
+        /// Outbound RTP.
+        /// </summary>
+        OutboundRtp = 0x0004,
+
+        /// <summary>
+        /// Remote inbound RTP.
+        /// </summary>
+        RemoteInboundRtp = 0x0008,
+
+        /// <summary>
+        /// Remote Outbound RTP.
+        /// </summary>
+        RemoteOutboundRtp = 0x0010,
+
+        /// <summary>
+        /// All types of WebRTC statistics.
+        /// </summary>
+        All = Codec | InboundRtp | OutboundRtp | RemoteInboundRtp | RemoteOutboundRtp
+    }
+
+    [Flags]
+    internal enum WebRTCStatisticsPropertyCategory
+    {
+        Common = 0x00000100,
+
+        Codec = 0x00000200,
+
+        RtpStream = 0x00000400,
+
+        ReceivedRtpStream = 0x00000800,
+
+        InboundRtpStream = 0x00001000,
+
+        SentRtpStream = 0x00002000,
+
+        OutboundRtpStream = 0x00004000,
+
+        RemoteInboundRtpStream = 0x00008000,
+
+        RemoteOutboundRtpStream = 0x00010000
+    }
+
+    /// <summary>
+    /// Specifies the WebRTC statistics property.
+    /// </summary>
+    /// <since_tizen> 10 </since_tizen>
+    public enum WebRTCStatisticsProperty
+    {
+        /// <summary>
+        /// Timestamp.
+        /// </summary>
+        Timestamp = WebRTCStatisticsPropertyCategory.Common | 0x01,
+
+        /// <summary>
+        /// ID.
+        /// </summary>
+        Id = WebRTCStatisticsPropertyCategory.Common | 0x02,
+
+        /// <summary>
+        /// Payload type.
+        /// </summary>
+        PayloadType = WebRTCStatisticsPropertyCategory.Codec | 0x01,
+
+        /// <summary>
+        /// Clock rate.
+        /// </summary>
+        ClockRate = WebRTCStatisticsPropertyCategory.Codec | 0x02,
+
+        /// <summary>
+        /// The number of channels.
+        /// </summary>
+        Channels = WebRTCStatisticsPropertyCategory.Codec | 0x03,
+
+        /// <summary>
+        /// MIME type.
+        /// </summary>
+        MimeType = WebRTCStatisticsPropertyCategory.Codec | 0x04,
+
+        /// <summary>
+        /// Codec type.
+        /// </summary>
+        CodecType = WebRTCStatisticsPropertyCategory.Codec | 0x05,
+
+        /// <summary>
+        /// SDP FMTP line.
+        /// </summary>
+        SdpFmtpLine = WebRTCStatisticsPropertyCategory.Codec | 0x06,
+
+        /// <summary>
+        /// SSRC.
+        /// </summary>
+        Ssrc = WebRTCStatisticsPropertyCategory.RtpStream | 0x01,
+
+        /// <summary>
+        /// Transport ID.
+        /// </summary>
+        TransportId = WebRTCStatisticsPropertyCategory.RtpStream | 0x02,
+
+        /// <summary>
+        /// Codec ID.
+        /// </summary>
+        CodecId = WebRTCStatisticsPropertyCategory.RtpStream | 0x03,
+
+        /// <summary>
+        /// Received packet.
+        /// </summary>
+        PacketsReceived = WebRTCStatisticsPropertyCategory.ReceivedRtpStream | 0x01,
+
+        /// <summary>
+        /// Lost packet.
+        /// </summary>
+        PacketsLost = WebRTCStatisticsPropertyCategory.ReceivedRtpStream | 0x02,
+
+        /// <summary>
+        /// Discarted packet.
+        /// </summary>
+        PacketsDiscarded = WebRTCStatisticsPropertyCategory.ReceivedRtpStream | 0x03,
+
+        /// <summary>
+        /// Jitter.
+        /// </summary>
+        Jitter = WebRTCStatisticsPropertyCategory.ReceivedRtpStream | 0x05,
+
+        /// <summary>
+        /// Received bytes.
+        /// </summary>
+        BytesReceived = WebRTCStatisticsPropertyCategory.InboundRtpStream | 0x01,
+
+        /// <summary>
+        /// Duplicated packet.
+        /// </summary>
+        PacketsDuplicated = WebRTCStatisticsPropertyCategory.InboundRtpStream | 0x02,
+
+        /// <summary>
+        /// Sent bytes.
+        /// </summary>
+        BytesSent = WebRTCStatisticsPropertyCategory.SentRtpStream | 0x01,
+
+        /// <summary>
+        /// Sent packets.
+        /// </summary>
+        PacketsSent = WebRTCStatisticsPropertyCategory.SentRtpStream | 0x02,
+
+        /// <summary>
+        /// Remote ID.
+        /// </summary>
+        RemoteId = WebRTCStatisticsPropertyCategory.InboundRtpStream | WebRTCStatisticsPropertyCategory.OutboundRtpStream | 0x01,
+
+        /// <summary>
+        /// FIR count.
+        /// </summary>
+        FirCount = WebRTCStatisticsPropertyCategory.InboundRtpStream | WebRTCStatisticsPropertyCategory.OutboundRtpStream | 0x02,
+
+        /// <summary>
+        /// PLI count.
+        /// </summary>
+        PliCount = WebRTCStatisticsPropertyCategory.InboundRtpStream | WebRTCStatisticsPropertyCategory.OutboundRtpStream | 0x03,
+
+        /// <summary>
+        /// NACK count.
+        /// </summary>
+        NackCount = WebRTCStatisticsPropertyCategory.InboundRtpStream | WebRTCStatisticsPropertyCategory.OutboundRtpStream | 0x04,
+
+        /// <summary>
+        /// Round trip time.
+        /// </summary>
+        RoundTripTime = WebRTCStatisticsPropertyCategory.RemoteInboundRtpStream | 0x01,
+
+        /// <summary>
+        /// Lost fraction.
+        /// </summary>
+        FractionLost = WebRTCStatisticsPropertyCategory.RemoteInboundRtpStream | 0x02,
+
+        /// <summary>
+        /// Remote timestamp.
+        /// </summary>
+        RemoteTimestamp = WebRTCStatisticsPropertyCategory.OutboundRtpStream | 0x01,
+
+        /// <summary>
+        /// Local ID.
+        /// </summary>
+        LocalId = WebRTCStatisticsPropertyCategory.RemoteInboundRtpStream | WebRTCStatisticsPropertyCategory.RemoteOutboundRtpStream | 0x01
+    }
+
+    internal enum WebRTCStatsPropertyType
+    {
+        TypeBool,
+        TypeInt,
+        TypeUint,
+        TypeInt64,
+        TypeUint64,
+        TypeFloat,
+        TypeDouble,
+        TypeString
+    }
+}