[MediaController] Add new APIs for subtitle, 360 mode, display mode/rotation (#997)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Remoting / MediaController / MediaControlServer.cs
index cb36872..4b788b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2018 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.
@@ -19,6 +19,7 @@ using System.Collections.Generic;
 using System.Threading.Tasks;
 using Tizen.Applications;
 using Native = Interop.MediaControllerServer;
+using NativePlaylist = Interop.MediaControllerPlaylist;
 
 namespace Tizen.Multimedia.Remoting
 {
@@ -30,8 +31,9 @@ namespace Tizen.Multimedia.Remoting
     /// <since_tizen> 4 </since_tizen>
     public static partial class MediaControlServer
     {
-        private static IntPtr _handle = IntPtr.Zero;
+        private static IntPtr _handle;
         private static bool? _isRunning;
+        private static string _serverName;
 
         /// <summary>
         /// Gets a value indicating whether the server is running.
@@ -105,16 +107,20 @@ namespace Tizen.Multimedia.Remoting
 
             try
             {
-                RegisterPlaybackCommandReceivedEvent();
                 RegisterPlaybackActionCommandReceivedEvent();
                 RegisterPlaybackPositionCommandReceivedEvent();
                 RegisterPlaylistCommandReceivedEvent();
                 RegisterShuffleModeCommandReceivedEvent();
                 RegisterRepeatModeCommandReceivedEvent();
+                RegisterSubtitleModeCommandReceivedEvent();
+                RegisterMode360CommandReceivedEvent();
+                RegisterDisplayModeCommandReceivedEvent();
+                RegisterDisplayRotationCommandReceivedEvent();
                 RegisterCustomCommandReceivedEvent();
                 RegisterCommandCompletedEvent();
                 RegisterSearchCommandReceivedEvent();
 
+                _serverName = Application.Current.ApplicationInfo.ApplicationId;
                 _isRunning = true;
             }
             catch
@@ -122,6 +128,7 @@ namespace Tizen.Multimedia.Remoting
                 Native.Destroy(_handle);
                 _playbackCommandCallback = null;
                 _handle = IntPtr.Zero;
+                _serverName = null;
                 throw;
             }
         }
@@ -167,6 +174,34 @@ namespace Tizen.Multimedia.Remoting
         }
 
         /// <summary>
+        /// Gets the active clients.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <returns>the activated client ids.</returns>
+        /// <since_tizen> 5 </since_tizen>
+        public static IEnumerable<string> GetActivatedClients()
+        {
+            var clientIds = new List<string>();
+
+            Native.ActivatedClientCallback activatedClientCallback = (name, _) =>
+            {
+                clientIds.Add(name);
+                return true;
+            };
+
+            Native.ForeachActivatedClient(Handle, activatedClientCallback).
+                ThrowIfError("Failed to get activated client.");
+
+            return clientIds.AsReadOnly();
+        }
+
+
+        #region Set information
+        /// <summary>
         /// Updates playback state and playback position.</summary>
         /// <param name="state">The playback state.</param>
         /// <param name="position">The playback position in milliseconds.</param>
@@ -196,7 +231,10 @@ namespace Tizen.Multimedia.Remoting
 
         private static void SetMetadata(MediaControllerNativeAttribute attribute, string value)
         {
-            Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
+            if (value != null)
+            {
+                Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
+            }
         }
 
         /// <summary>
@@ -228,6 +266,9 @@ namespace Tizen.Multimedia.Remoting
             SetMetadata(MediaControllerNativeAttribute.Description, metadata.Description);
             SetMetadata(MediaControllerNativeAttribute.TrackNumber, metadata.TrackNumber);
             SetMetadata(MediaControllerNativeAttribute.Picture, metadata.AlbumArtPath);
+            SetMetadata(MediaControllerNativeAttribute.Season, metadata.EncodedSeason);
+            SetMetadata(MediaControllerNativeAttribute.Episode, metadata.EncodedEpisode);
+            SetMetadata(MediaControllerNativeAttribute.Resolution, metadata.EncodedResolution);
 
             Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
         }
@@ -267,31 +308,6 @@ namespace Tizen.Multimedia.Remoting
         }
 
         /// <summary>
-        /// Sets the index of current playing media.
-        /// </summary>
-        /// <param name="index">The index of current playing media.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
-        /// <exception cref="InvalidOperationException">
-        ///     The server is not running .<br/>
-        ///     -or-<br/>
-        ///     An internal error occurs.
-        /// </exception>
-        /// <since_tizen> 5 </since_tizen>
-        [Obsolete("Please do not use! This will be deprecated. Please use SetInfoOfCurrentPlayingMedia instead.")]
-        public static void SetIndexOfCurrentPlayingMedia(string index)
-        {
-            if (index == null)
-            {
-                throw new ArgumentNullException(nameof(index));
-            }
-
-            Native.SetIndexOfCurrentPlayingMedia(Handle, index)
-                .ThrowIfError("Failed to set the index of current playing media");
-
-            Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
-        }
-
-        /// <summary>
         /// Sets the playlist name and index of current playing media.
         /// </summary>
         /// <param name="playlistName">The playlist name of current playing media.</param>
@@ -323,175 +339,160 @@ namespace Tizen.Multimedia.Remoting
         }
 
         /// <summary>
-        /// Delete playlist.
+        /// Sets the age rating of latest played media.
         /// </summary>
-        /// <param name="playlist">The name of playlist.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="playlist"/> is null.</exception>
+        /// <param name="ageRating">
+        /// The Age rating of latest played media. The valid range is 0 to 19, inclusive.
+        /// Especially, 0 means that media is suitable for all ages.
+        /// </param>
+        /// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="ageRating"/> is not valid.</exception>
         /// <exception cref="InvalidOperationException">
         ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
         /// <since_tizen> 5 </since_tizen>
-        public static void RemovePlaylist(MediaControlPlaylist playlist)
+        public static void SetAgeRating(int ageRating)
         {
-            if (playlist == null)
+            if (ageRating < 0 || ageRating > 19)
             {
-                throw new ArgumentNullException(nameof(playlist));
+                throw new ArgumentOutOfRangeException(nameof(ageRating));
             }
 
-            Native.DeletePlaylist(Handle, playlist.Handle);
-            playlist.Dispose();
+            Native.SetAgeRating(Handle, ageRating).ThrowIfError("Failed to set age rating.");
+
+            Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
         }
 
-        // Saves the playlist to the persistent storage.
-        internal static void SavePlaylist(IntPtr playlistHandle)
+        /// <summary>
+        /// Sets the subtitle mode.
+        /// </summary>
+        /// <param name="isEnabled">A value indicating whether the subtitle mode is enabled.</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetSubtitleMode(bool isEnabled)
         {
-            Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
+            Native.UpdateSubtitleMode(Handle, isEnabled).ThrowIfError("Failed to set subtitle mode.");
         }
 
-        // Gets the playlist handle by name.
-        internal static IntPtr GetPlaylistHandle(string name)
+        /// <summary>
+        /// Sets the 360 mode.
+        /// </summary>
+        /// <param name="isEnabled">A value indicating whether the 360 mode is enabled.</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetMode360(bool isEnabled)
         {
-            Native.GetPlaylistHandle(Handle, name, out IntPtr playlistHandle)
-                .ThrowIfError("Failed to get playlist handle by name");
-
-            return playlistHandle;
+            Native.UpdateMode360(Handle, isEnabled).ThrowIfError("Failed to set 360 mode.");
         }
 
         /// <summary>
-        /// Gets the active clients.
+        /// Sets the display mode.
         /// </summary>
+        /// <param name="mode">A value indicating the <see cref="MediaControlDisplayMode"/>.</param>
         /// <exception cref="InvalidOperationException">
         ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
-        /// <returns>the activated client ids.</returns>
-        /// <since_tizen> 5 </since_tizen>
-        public static IEnumerable<string> GetActivatedClients()
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayMode(MediaControlDisplayMode mode)
         {
-            var clientIds = new List<string>();
-
-            Native.ActivatedClientCallback activatedClientCallback = (name, _) =>
-            {
-                clientIds.Add(name);
-                return true;
-            };
-
-            Native.ForeachActivatedClient(Handle, activatedClientCallback).
-                ThrowIfError("Failed to get activated client.");
-
-            return clientIds.AsReadOnly();
+            Native.UpdateDisplayMode(Handle, mode.ToNative()).ThrowIfError("Failed to set display mode.");
         }
 
         /// <summary>
-        /// Requests commands to the client.
+        /// Sets the display rotation.
         /// </summary>
-        /// <remarks>
-        /// The client can request the command to execute <see cref="Command"/>, <br/>
-        /// and then, the server receive the result of each request(command).
-        /// </remarks>
-        /// <param name="command">A <see cref="Command"/> class.</param>
-        /// <param name="clientId">The client Id to send command.</param>
-        /// <returns><see cref="Bundle"/> represents the extra data from client and it can be null.</returns>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="command"/> or <paramref name="clientId"/> is null.
-        /// </exception>
+        /// <param name="rotation">A value indicating the <see cref="Rotation"/>.</param>
         /// <exception cref="InvalidOperationException">
-        ///     The server has already been stopped.<br/>
+        ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
-        /// <since_tizen> 5 </since_tizen>
-        public static async Task<Bundle> RequestAsync(Command command, string clientId)
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayRotation(Rotation rotation)
         {
-            if (command == null)
-            {
-                throw new ArgumentNullException(nameof(command));
-            }
-            if (clientId == null)
-            {
-                throw new ArgumentNullException(nameof(clientId));
-            }
-
-            command.SetRequestInformation(clientId);
-
-            var tcs = new TaskCompletionSource<MediaControllerError>();
-            string reqeustId = null;
-            Bundle bundle = null;
-
-            EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
-            {
-                if (e.RequestId == reqeustId)
-                {
-                    bundle = e.Bundle;
-                    tcs.TrySetResult(e.Result);
-                }
-            };
-
-            try
-            {
-                CommandCompleted += eventHandler;
-
-                reqeustId = command.Request(Handle);
-
-                (await tcs.Task).ThrowIfError("Failed to request event.");
-
-                return bundle;
-            }
-            finally
-            {
-                CommandCompleted -= eventHandler;
-            }
+            Native.UpdateDisplayRotaton(Handle, rotation.ToNative()).ThrowIfError("Failed to set display rotation.");
         }
 
         /// <summary>
-        /// Sends the result of each command.
+        /// Sets the index of current playing media.
         /// </summary>
-        /// <param name="command">The command that return to client.</param>
-        /// <param name="result">The result of <paramref name="command"/>.</param>
-        /// <param name="bundle">The extra data.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
+        /// <param name="index">The index of current playing media.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
         /// <exception cref="InvalidOperationException">
         ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
         /// <since_tizen> 5 </since_tizen>
-        public static void Response(Command command, int result, Bundle bundle)
+        [Obsolete("Please do not use! This will be deprecated. Please use SetInfoOfCurrentPlayingMedia instead.")]
+        public static void SetIndexOfCurrentPlayingMedia(string index)
         {
-            if (command == null)
+            if (index == null)
             {
-                throw new ArgumentNullException(nameof(command));
+                throw new ArgumentNullException(nameof(index));
             }
 
-            command.Response(Handle, result, bundle);
+            Native.SetIndexOfCurrentPlayingMedia(Handle, index)
+                .ThrowIfError("Failed to set the index of current playing media");
+
+            Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
         }
+        #endregion Set information
 
+
+        #region Playlist
         /// <summary>
-        /// Sends the result of each command.
+        /// Delete playlist.
         /// </summary>
-        /// <param name="command">The command that return to client.</param>
-        /// <param name="result">The result of <paramref name="command"/>.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
+        /// <remarks>Currently, only server can remove the playlist.</remarks>
+        /// <param name="playlist">The name of playlist.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="playlist"/> is null.</exception>
         /// <exception cref="InvalidOperationException">
         ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
         /// <since_tizen> 5 </since_tizen>
-        public static void Response(Command command, int result)
+        public static void RemovePlaylist(MediaControlPlaylist playlist)
         {
-            if (command == null)
+            if (playlist == null)
             {
-                throw new ArgumentNullException(nameof(command));
+                throw new ArgumentNullException(nameof(playlist));
             }
 
-            command.Response(Handle, result, null);
+            Native.DeletePlaylist(Handle, playlist.Handle);
+            playlist.Dispose();
+        }
+
+        // Saves the playlist to the persistent storage.
+        internal static void SavePlaylist(IntPtr playlistHandle)
+        {
+            Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
+        }
+
+        // Gets the playlist handle by name.
+        internal static IntPtr GetPlaylistHandle(string name)
+        {
+            NativePlaylist.GetPlaylistHandle(_serverName, name, out IntPtr playlistHandle).
+                ThrowIfError("Failed to get playlist handle by name");
+
+            return playlistHandle;
         }
+        #endregion Playlist
 
-        #region Capabilities
+
+        #region Capability
         /// <summary>
         /// Sets the content type of latest played media.
         /// </summary>
@@ -596,11 +597,12 @@ namespace Tizen.Multimedia.Remoting
         {
             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
 
-            Native.SetShuffleModeCapability(Handle, support).ThrowIfError("Failed to set shuffle mode capability.");
+            Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Shuffle, support).
+                ThrowIfError("Failed to set shuffle mode capability.");
         }
 
         /// <summary>
-        /// Sets the content type of latest played media.
+        /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating repeat mode is supported or not.
         /// </summary>
         /// <param name="support">A value indicating whether the <see cref="MediaControlRepeatMode"/> is supported or not.</param>
         /// <exception cref="InvalidOperationException">
@@ -614,34 +616,224 @@ namespace Tizen.Multimedia.Remoting
         {
             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
 
-            Native.SetRepeatModeCapability(Handle, support).ThrowIfError("Failed to set shuffle mode capability.");
+            Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Repeat, support).
+                ThrowIfError("Failed to set repeat mode capability.");
         }
-        #endregion Capabilities
 
         /// <summary>
-        /// Sets the age rating of latest played media.
+        /// Sets the supported list of <see cref="MediaControlDisplayMode"/>.
         /// </summary>
-        /// <param name="ageRating">
-        /// The Age rating of latest played media. The valid range is 0 to 19, inclusive.
-        /// Especially, 0 means that media is suitable for all ages.
-        /// </param>
-        /// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="ageRating"/> is not valid.</exception>
+        /// <remarks>
+        /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.
+        /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
+        /// </remarks>
+        /// <param name="capabilities">The supported list of <see cref="MediaControlDisplayMode"/>.</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayModeCapabilities(IDictionary<MediaControlDisplayMode, MediaControlCapabilitySupport> capabilities)
+        {
+            foreach (var pair in capabilities)
+            {
+                SetDisplayModeCapability(pair.Key, pair.Value);
+            }
+        }
+
+        /// <summary>
+        /// Sets the <paramref name="mode"/> is supported or not.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.<br/>
+        /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
+        /// </remarks>
+        /// <param name="mode">The <see cref="MediaControlDisplayMode"/>.</param>
+        /// <param name="support">A value indicating whether the <paramref name="mode"/> is supported or not.</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <exception cref="ArgumentException"><paramref name="mode"/> or <paramref name="support"/> is invalid.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayModeCapability(MediaControlDisplayMode mode, MediaControlCapabilitySupport support)
+        {
+            ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
+            ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
+
+            if (support == MediaControlCapabilitySupport.NotDecided)
+            {
+                throw new ArgumentException($"NotDecided is not allowed in {mode} capability.");
+            }
+
+            Native.SetDisplayModeCapability(Handle, (uint)mode.ToNative(), support).
+                ThrowIfError("Failed to set display mode capability.");
+        }
+
+        /// <summary>
+        /// Sets the supported list of <see cref="Rotation"/>.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
+        /// The default value of each <see cref="Rotation"/> is not supported.
+        /// </remarks>
+        /// <param name="capabilities">The supported list of <see cref="Rotation"/>.</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayRotationCapabilities(IDictionary<Rotation, MediaControlCapabilitySupport> capabilities)
+        {
+            foreach (var pair in capabilities)
+            {
+                SetDisplayRotationCapability(pair.Key, pair.Value);
+            }
+        }
+
+        /// <summary>
+        /// Sets the <paramref name="rotation"/> is supported or not.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
+        /// The default value of each <see cref="Rotation"/> is not supported.
+        /// </remarks>
+        /// <param name="rotation">The <see cref="Rotation"/>.</param>
+        /// <param name="support">A value indicating whether the <paramref name="rotation"/> is supported or not..</param>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <exception cref="ArgumentException"><paramref name="rotation"/> or <paramref name="support"/> is invalid.</exception>
+        /// <since_tizen> 6 </since_tizen>
+        public static void SetDisplayRotationCapability(Rotation rotation, MediaControlCapabilitySupport support)
+        {
+            ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
+            ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
+
+            if (support == MediaControlCapabilitySupport.NotDecided)
+            {
+                throw new ArgumentException($"NotDecided is not allowed in {rotation} capability.");
+            }
+
+            Native.SetDisplayRotationCapability(Handle, (uint)rotation.ToNative(), support).
+                ThrowIfError("Failed to set display rotation capability.");
+        }
+        #endregion Capability
+
+
+        #region Command
+        /// <summary>
+        /// Requests commands to the client.
+        /// </summary>
+        /// <remarks>
+        /// The client can request the command to execute <see cref="Command"/>, <br/>
+        /// and then, the server receive the result of each request(command).
+        /// </remarks>
+        /// <param name="command">A <see cref="Command"/> class.</param>
+        /// <param name="clientId">The client Id to send command.</param>
+        /// <returns><see cref="Bundle"/> represents the extra data from client and it can be null.</returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="command"/> or <paramref name="clientId"/> is null.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        ///     The server has already been stopped.<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <since_tizen> 5 </since_tizen>
+        public static async Task<Bundle> RequestAsync(Command command, string clientId)
+        {
+            if (command == null)
+            {
+                throw new ArgumentNullException(nameof(command));
+            }
+            if (clientId == null)
+            {
+                throw new ArgumentNullException(nameof(clientId));
+            }
+
+            command.SetRequestInformation(clientId);
+
+            var tcs = new TaskCompletionSource<MediaControllerError>();
+            string reqeustId = null;
+            Bundle bundle = null;
+
+            EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
+            {
+                if (e.RequestId == reqeustId)
+                {
+                    bundle = e.Bundle;
+                    tcs.TrySetResult(e.Result);
+                }
+            };
+
+            try
+            {
+                CommandCompleted += eventHandler;
+
+                reqeustId = command.Request(Handle);
+
+                (await tcs.Task).ThrowIfError("Failed to request event.");
+
+                return bundle;
+            }
+            finally
+            {
+                CommandCompleted -= eventHandler;
+            }
+        }
+
+        /// <summary>
+        /// Sends the result of each command.
+        /// </summary>
+        /// <param name="command">The command that return to client.</param>
+        /// <param name="result">The result of <paramref name="command"/>.</param>
+        /// <param name="bundle">The extra data.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
         /// <exception cref="InvalidOperationException">
         ///     The server is not running .<br/>
         ///     -or-<br/>
         ///     An internal error occurs.
         /// </exception>
         /// <since_tizen> 5 </since_tizen>
-        public static void SetAgeRating(int ageRating)
+        public static void Response(Command command, int result, Bundle bundle)
         {
-            if (ageRating < 0 || ageRating > 19)
+            if (command == null)
             {
-                throw new ArgumentOutOfRangeException(nameof(ageRating));
+                throw new ArgumentNullException(nameof(command));
             }
 
-            Native.SetAgeRating(Handle, ageRating).ThrowIfError("Failed to set age rating.");
+            command.Response(Handle, result, bundle);
+        }
 
-            Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
+        /// <summary>
+        /// Sends the result of each command.
+        /// </summary>
+        /// <param name="command">The command that return to client.</param>
+        /// <param name="result">The result of <paramref name="command"/>.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     The server is not running .<br/>
+        ///     -or-<br/>
+        ///     An internal error occurs.
+        /// </exception>
+        /// <since_tizen> 5 </since_tizen>
+        public static void Response(Command command, int result)
+        {
+            if (command == null)
+            {
+                throw new ArgumentNullException(nameof(command));
+            }
+
+            command.Response(Handle, result, null);
         }
+        #endregion Command
     }
 }
\ No newline at end of file