[MediaController] Add capability method for subtitle, 360 mode (#1048)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Remoting / MediaController / MediaControlServer.cs
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Threading.Tasks;
20 using Tizen.Applications;
21 using Native = Interop.MediaControllerServer;
22 using NativePlaylist = Interop.MediaControllerPlaylist;
23
24 namespace Tizen.Multimedia.Remoting
25 {
26     /// <summary>
27     /// Provides a means to set playback information and metadata and receive commands from clients.
28     /// </summary>
29     /// <seealso cref="MediaControllerManager"/>
30     /// <seealso cref="MediaController"/>
31     /// <since_tizen> 4 </since_tizen>
32     public static partial class MediaControlServer
33     {
34         private static IntPtr _handle;
35         private static bool? _isRunning;
36         private static string _serverName;
37
38         /// <summary>
39         /// Gets a value indicating whether the server is running.
40         /// </summary>
41         /// <value>true if the server has started; otherwise, false.</value>
42         /// <seealso cref="Start"/>
43         /// <seealso cref="Stop"/>
44         /// <since_tizen> 4 </since_tizen>
45         public static bool IsRunning
46         {
47             get
48             {
49                 if (_isRunning.HasValue == false)
50                 {
51                     _isRunning = GetRunningState();
52                 }
53
54                 return _isRunning.Value;
55             }
56         }
57
58         private static bool GetRunningState()
59         {
60             IntPtr handle = IntPtr.Zero;
61             try
62             {
63                 Native.ConnectDb(out handle).ThrowIfError("Failed to retrieve the running state.");
64
65                 Native.CheckServerExist(handle, Applications.Application.Current.ApplicationInfo.ApplicationId,
66                     out var value).ThrowIfError("Failed to retrieve the running state.");
67
68                 return value;
69             }
70             finally
71             {
72                 if (handle != IntPtr.Zero)
73                 {
74                     Native.DisconnectDb(handle);
75                 }
76             }
77         }
78
79         private static void EnsureInitializedIfRunning()
80         {
81             if (_handle != IntPtr.Zero)
82             {
83                 return;
84             }
85
86             if (IsRunning == false)
87             {
88                 throw new InvalidOperationException("The server is not running.");
89             }
90
91             Initialize();
92         }
93
94         private static IntPtr Handle
95         {
96             get
97             {
98                 EnsureInitializedIfRunning();
99
100                 return _handle;
101             }
102         }
103
104         private static void Initialize()
105         {
106             Native.Create(out _handle).ThrowIfError("Failed to create media controller server.");
107
108             try
109             {
110                 RegisterPlaybackActionCommandReceivedEvent();
111                 RegisterPlaybackPositionCommandReceivedEvent();
112                 RegisterPlaylistCommandReceivedEvent();
113                 RegisterShuffleModeCommandReceivedEvent();
114                 RegisterRepeatModeCommandReceivedEvent();
115                 RegisterSubtitleModeCommandReceivedEvent();
116                 RegisterMode360CommandReceivedEvent();
117                 RegisterDisplayModeCommandReceivedEvent();
118                 RegisterDisplayRotationCommandReceivedEvent();
119                 RegisterCustomCommandReceivedEvent();
120                 RegisterCommandCompletedEvent();
121                 RegisterSearchCommandReceivedEvent();
122
123                 _serverName = Application.Current.ApplicationInfo.ApplicationId;
124                 _isRunning = true;
125             }
126             catch
127             {
128                 Native.Destroy(_handle);
129                 _playbackCommandCallback = null;
130                 _handle = IntPtr.Zero;
131                 _serverName = null;
132                 throw;
133             }
134         }
135
136         /// <summary>
137         /// Starts the media control server.
138         /// </summary>
139         /// <remarks>
140         /// When the server starts, <see cref="MediaControllerManager.ServerStarted"/> will be raised.
141         /// </remarks>
142         /// <privilege>http://tizen.org/privilege/mediacontroller.server</privilege>
143         /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
144         /// <exception cref="UnauthorizedAccessException">Caller does not have required privilege.</exception>
145         /// <seealso cref="MediaControllerManager.ServerStarted"/>
146         /// <since_tizen> 4 </since_tizen>
147         public static void Start()
148         {
149             Initialize();
150         }
151
152         /// <summary>
153         /// Stops the media control server.
154         /// </summary>
155         /// <remarks>
156         /// When the server stops, <see cref="MediaControllerManager.ServerStopped"/> will be raised.
157         /// </remarks>
158         /// <exception cref="InvalidOperationException">
159         ///     The server is not running .<br/>
160         ///     -or-<br/>
161         ///     An internal error occurs.
162         /// </exception>
163         /// <seealso cref="MediaControllerManager.ServerStopped"/>
164         /// <since_tizen> 4 </since_tizen>
165         public static void Stop()
166         {
167             EnsureInitializedIfRunning();
168
169             Native.Destroy(_handle).ThrowIfError("Failed to stop the server.");
170
171             _handle = IntPtr.Zero;
172             _playbackCommandCallback = null;
173             _isRunning = false;
174         }
175
176         /// <summary>
177         /// Gets the active clients.
178         /// </summary>
179         /// <exception cref="InvalidOperationException">
180         ///     The server is not running .<br/>
181         ///     -or-<br/>
182         ///     An internal error occurs.
183         /// </exception>
184         /// <returns>the activated client ids.</returns>
185         /// <since_tizen> 5 </since_tizen>
186         public static IEnumerable<string> GetActivatedClients()
187         {
188             var clientIds = new List<string>();
189
190             Native.ActivatedClientCallback activatedClientCallback = (name, _) =>
191             {
192                 clientIds.Add(name);
193                 return true;
194             };
195
196             Native.ForeachActivatedClient(Handle, activatedClientCallback).
197                 ThrowIfError("Failed to get activated client.");
198
199             return clientIds.AsReadOnly();
200         }
201
202
203         #region Set information
204         /// <summary>
205         /// Updates playback state and playback position.</summary>
206         /// <param name="state">The playback state.</param>
207         /// <param name="position">The playback position in milliseconds.</param>
208         /// <exception cref="ArgumentException"><paramref name="state"/> is not valid.</exception>
209         /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero.</exception>
210         /// <exception cref="InvalidOperationException">
211         ///     The server is not running .<br/>
212         ///     -or-<br/>
213         ///     An internal error occurs.
214         /// </exception>
215         /// <since_tizen> 4 </since_tizen>
216         public static void SetPlaybackState(MediaControlPlaybackState state, long position)
217         {
218             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackState), state, nameof(state));
219
220             if (position < 0)
221             {
222                 throw new ArgumentOutOfRangeException(nameof(position), position, "position can't be less than zero.");
223             }
224
225             Native.SetPlaybackState(Handle, state.ToNative()).ThrowIfError("Failed to set playback state.");
226
227             Native.SetPlaybackPosition(Handle, (ulong)position).ThrowIfError("Failed to set playback position.");
228
229             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
230         }
231
232         private static void SetMetadata(MediaControllerNativeAttribute attribute, string value)
233         {
234             if (value != null)
235             {
236                 Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
237             }
238         }
239
240         /// <summary>
241         /// Updates metadata information.
242         /// </summary>
243         /// <param name="metadata">The metadata to update.</param>
244         /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception>
245         /// <exception cref="InvalidOperationException">
246         ///     The server is not running .<br/>
247         ///     -or-<br/>
248         ///     An internal error occurs.
249         /// </exception>
250         /// <since_tizen> 4 </since_tizen>
251         public static void SetMetadata(MediaControlMetadata metadata)
252         {
253             if (metadata == null)
254             {
255                 throw new ArgumentNullException(nameof(metadata));
256             }
257
258             SetMetadata(MediaControllerNativeAttribute.Title, metadata.Title);
259             SetMetadata(MediaControllerNativeAttribute.Artist, metadata.Artist);
260             SetMetadata(MediaControllerNativeAttribute.Album, metadata.Album);
261             SetMetadata(MediaControllerNativeAttribute.Author, metadata.Author);
262             SetMetadata(MediaControllerNativeAttribute.Genre, metadata.Genre);
263             SetMetadata(MediaControllerNativeAttribute.Duration, metadata.Duration);
264             SetMetadata(MediaControllerNativeAttribute.Date, metadata.Date);
265             SetMetadata(MediaControllerNativeAttribute.Copyright, metadata.Copyright);
266             SetMetadata(MediaControllerNativeAttribute.Description, metadata.Description);
267             SetMetadata(MediaControllerNativeAttribute.TrackNumber, metadata.TrackNumber);
268             SetMetadata(MediaControllerNativeAttribute.Picture, metadata.AlbumArtPath);
269             SetMetadata(MediaControllerNativeAttribute.Season, metadata.EncodedSeason);
270             SetMetadata(MediaControllerNativeAttribute.Episode, metadata.EncodedEpisode);
271             SetMetadata(MediaControllerNativeAttribute.Resolution, metadata.EncodedResolution);
272
273             Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
274         }
275
276         /// <summary>
277         /// Updates the shuffle mode.
278         /// </summary>
279         /// <param name="enabled">A value indicating whether the shuffle mode is enabled.</param>
280         /// <exception cref="InvalidOperationException">
281         ///     The server is not running .<br/>
282         ///     -or-<br/>
283         ///     An internal error occurs.
284         /// </exception>
285         /// <since_tizen> 4 </since_tizen>
286         public static void SetShuffleModeEnabled(bool enabled)
287         {
288             Native.UpdateShuffleMode(Handle, enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off).
289                 ThrowIfError("Failed to set shuffle mode.");
290         }
291
292         /// <summary>
293         /// Updates the repeat mode.
294         /// </summary>
295         /// <param name="mode">A value indicating the repeat mode.</param>
296         /// <exception cref="InvalidOperationException">
297         ///     The server is not running .<br/>
298         ///     -or-<br/>
299         ///     An internal error occurs.
300         /// </exception>
301         /// <exception cref="ArgumentException"><paramref name="mode"/> is invalid.</exception>
302         /// <since_tizen> 4 </since_tizen>
303         public static void SetRepeatMode(MediaControlRepeatMode mode)
304         {
305             ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
306
307             Native.UpdateRepeatMode(Handle, mode.ToNative()).ThrowIfError("Failed to set repeat mode.");
308         }
309
310         /// <summary>
311         /// Sets the playlist name and index of current playing media.
312         /// </summary>
313         /// <param name="playlistName">The playlist name of current playing media.</param>
314         /// <param name="index">The index of current playing media.</param>
315         /// <exception cref="ArgumentNullException">
316         /// <paramref name="playlistName"/> or <paramref name="index"/> is null.
317         /// </exception>
318         /// <exception cref="InvalidOperationException">
319         ///     The server is not running .<br/>
320         ///     -or-<br/>
321         ///     An internal error occurs.
322         /// </exception>
323         /// <since_tizen> 5 </since_tizen>
324         public static void SetInfoOfCurrentPlayingMedia(string playlistName, string index)
325         {
326             if (playlistName == null)
327             {
328                 throw new ArgumentNullException(nameof(playlistName));
329             }
330             if (index == null)
331             {
332                 throw new ArgumentNullException(nameof(index));
333             }
334
335             Native.SetInfoOfCurrentPlayingMedia(Handle, playlistName, index)
336                 .ThrowIfError("Failed to set the playlist name and index of current playing media");
337
338             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
339         }
340
341         /// <summary>
342         /// Sets the age rating of latest played media.
343         /// </summary>
344         /// <param name="ageRating">
345         /// The Age rating of latest played media. The valid range is 0 to 19, inclusive.
346         /// Especially, 0 means that media is suitable for all ages.
347         /// </param>
348         /// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="ageRating"/> is not valid.</exception>
349         /// <exception cref="InvalidOperationException">
350         ///     The server is not running .<br/>
351         ///     -or-<br/>
352         ///     An internal error occurs.
353         /// </exception>
354         /// <since_tizen> 5 </since_tizen>
355         public static void SetAgeRating(int ageRating)
356         {
357             if (ageRating < 0 || ageRating > 19)
358             {
359                 throw new ArgumentOutOfRangeException(nameof(ageRating));
360             }
361
362             Native.SetAgeRating(Handle, ageRating).ThrowIfError("Failed to set age rating.");
363
364             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
365         }
366
367         /// <summary>
368         /// Sets the subtitle mode.
369         /// </summary>
370         /// <param name="isEnabled">A value indicating whether the subtitle mode is enabled.</param>
371         /// <exception cref="InvalidOperationException">
372         ///     The server is not running .<br/>
373         ///     -or-<br/>
374         ///     An internal error occurs.
375         /// </exception>
376         /// <since_tizen> 6 </since_tizen>
377         public static void SetSubtitleMode(bool isEnabled)
378         {
379             Native.UpdateSubtitleMode(Handle, isEnabled).ThrowIfError("Failed to set subtitle mode.");
380         }
381
382         /// <summary>
383         /// Sets the 360 mode.
384         /// </summary>
385         /// <param name="isEnabled">A value indicating whether the 360 mode is enabled.</param>
386         /// <exception cref="InvalidOperationException">
387         ///     The server is not running .<br/>
388         ///     -or-<br/>
389         ///     An internal error occurs.
390         /// </exception>
391         /// <since_tizen> 6 </since_tizen>
392         public static void SetMode360(bool isEnabled)
393         {
394             Native.UpdateMode360(Handle, isEnabled).ThrowIfError("Failed to set 360 mode.");
395         }
396
397         /// <summary>
398         /// Sets the display mode.
399         /// </summary>
400         /// <param name="mode">A value indicating the <see cref="MediaControlDisplayMode"/>.</param>
401         /// <exception cref="InvalidOperationException">
402         ///     The server is not running .<br/>
403         ///     -or-<br/>
404         ///     An internal error occurs.
405         /// </exception>
406         /// <since_tizen> 6 </since_tizen>
407         public static void SetDisplayMode(MediaControlDisplayMode mode)
408         {
409             Native.UpdateDisplayMode(Handle, mode.ToNative()).ThrowIfError("Failed to set display mode.");
410         }
411
412         /// <summary>
413         /// Sets the display rotation.
414         /// </summary>
415         /// <param name="rotation">A value indicating the <see cref="Rotation"/>.</param>
416         /// <exception cref="InvalidOperationException">
417         ///     The server is not running .<br/>
418         ///     -or-<br/>
419         ///     An internal error occurs.
420         /// </exception>
421         /// <since_tizen> 6 </since_tizen>
422         public static void SetDisplayRotation(Rotation rotation)
423         {
424             Native.UpdateDisplayRotaton(Handle, rotation.ToNative()).ThrowIfError("Failed to set display rotation.");
425         }
426
427         /// <summary>
428         /// Sets the index of current playing media.
429         /// </summary>
430         /// <param name="index">The index of current playing media.</param>
431         /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
432         /// <exception cref="InvalidOperationException">
433         ///     The server is not running .<br/>
434         ///     -or-<br/>
435         ///     An internal error occurs.
436         /// </exception>
437         /// <since_tizen> 5 </since_tizen>
438         [Obsolete("Please do not use! This will be deprecated. Please use SetInfoOfCurrentPlayingMedia instead.")]
439         public static void SetIndexOfCurrentPlayingMedia(string index)
440         {
441             if (index == null)
442             {
443                 throw new ArgumentNullException(nameof(index));
444             }
445
446             Native.SetIndexOfCurrentPlayingMedia(Handle, index)
447                 .ThrowIfError("Failed to set the index of current playing media");
448
449             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
450         }
451         #endregion Set information
452
453
454         #region Playlist
455         /// <summary>
456         /// Delete playlist.
457         /// </summary>
458         /// <remarks>Currently, only server can remove the playlist.</remarks>
459         /// <param name="playlist">The name of playlist.</param>
460         /// <exception cref="ArgumentNullException"><paramref name="playlist"/> is null.</exception>
461         /// <exception cref="InvalidOperationException">
462         ///     The server is not running .<br/>
463         ///     -or-<br/>
464         ///     An internal error occurs.
465         /// </exception>
466         /// <since_tizen> 5 </since_tizen>
467         public static void RemovePlaylist(MediaControlPlaylist playlist)
468         {
469             if (playlist == null)
470             {
471                 throw new ArgumentNullException(nameof(playlist));
472             }
473
474             Native.DeletePlaylist(Handle, playlist.Handle);
475             playlist.Dispose();
476         }
477
478         // Saves the playlist to the persistent storage.
479         internal static void SavePlaylist(IntPtr playlistHandle)
480         {
481             Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
482         }
483
484         // Gets the playlist handle by name.
485         internal static IntPtr GetPlaylistHandle(string name)
486         {
487             NativePlaylist.GetPlaylistHandle(_serverName, name, out IntPtr playlistHandle).
488                 ThrowIfError("Failed to get playlist handle by name");
489
490             return playlistHandle;
491         }
492         #endregion Playlist
493
494
495         #region Capability
496         /// <summary>
497         /// Sets the content type of latest played media.
498         /// </summary>
499         /// <param name="type">A value indicating the content type of the latest played media.</param>
500         /// <exception cref="InvalidOperationException">
501         ///     The server is not running .<br/>
502         ///     -or-<br/>
503         ///     An internal error occurs.
504         /// </exception>
505         /// <exception cref="ArgumentException"><paramref name="type"/> is invalid.</exception>
506         /// <since_tizen> 5 </since_tizen>
507         public static void SetPlaybackContentType(MediaControlContentType type)
508         {
509             ValidationUtil.ValidateEnum(typeof(MediaControlContentType), type, nameof(type));
510
511             Native.SetPlaybackContentType(Handle, type).ThrowIfError("Failed to set playback content type.");
512
513             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
514         }
515
516         /// <summary>
517         /// Sets the path of icon.
518         /// </summary>
519         /// <param name="path">The path of icon.</param>
520         /// <exception cref="InvalidOperationException">
521         ///     The server is not running .<br/>
522         ///     -or-<br/>
523         ///     An internal error occurs.
524         /// </exception>
525         /// <exception cref="ArgumentNullException"><paramref name="path"/> is invalid.</exception>
526         /// <since_tizen> 5 </since_tizen>
527         public static void SetIconPath(string path)
528         {
529             if (path == null)
530             {
531                 throw new ArgumentNullException(nameof(path));
532             }
533
534             Native.SetIconPath(Handle, path).ThrowIfError("Failed to set uri path.");
535         }
536
537         /// <summary>
538         /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
539         /// </summary>
540         /// <param name="capabilities">The set of <see cref="MediaControlPlaybackCommand"/> and <see cref="MediaControlCapabilitySupport"/>.</param>
541         /// <exception cref="InvalidOperationException">
542         ///     The server is not running .<br/>
543         ///     -or-<br/>
544         ///     An internal error occurs.
545         /// </exception>
546         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
547         /// <since_tizen> 5 </since_tizen>
548         public static void SetPlaybackCapabilities(Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport> capabilities)
549         {
550             foreach (var pair in capabilities)
551             {
552                 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), pair.Key, nameof(pair.Key));
553                 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), pair.Value, nameof(pair.Value));
554
555                 SetPlaybackCapability(pair.Key, pair.Value);
556                 Native.SetPlaybackCapability(Handle, pair.Key.ToNative(), pair.Value).
557                     ThrowIfError("Failed to set playback capability.");
558             }
559
560             Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
561         }
562
563         /// <summary>
564         /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
565         /// </summary>
566         /// <param name="action">A playback command.</param>
567         /// <param name="support">A value indicating whether the <paramref name="action"/> is supported or not.</param>
568         /// <exception cref="InvalidOperationException">
569         ///     The server is not running .<br/>
570         ///     -or-<br/>
571         ///     An internal error occurs.
572         /// </exception>
573         /// <exception cref="ArgumentException"><paramref name="action"/> or <paramref name="support"/> is invalid.</exception>
574         /// <since_tizen> 5 </since_tizen>
575         public static void SetPlaybackCapability(MediaControlPlaybackCommand action, MediaControlCapabilitySupport support)
576         {
577             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
578             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
579
580             Native.SetPlaybackCapability(Handle, action.ToNative(), support).ThrowIfError("Failed to set playback capability.");
581
582             Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
583         }
584
585         /// <summary>
586         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating shuffle mode is supported or not.
587         /// </summary>
588         /// <param name="support">A value indicating whether the shuffle mode is supported or not.</param>
589         /// <exception cref="InvalidOperationException">
590         ///     The server is not running .<br/>
591         ///     -or-<br/>
592         ///     An internal error occurs.
593         /// </exception>
594         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
595         /// <since_tizen> 5 </since_tizen>
596         public static void SetShuffleModeCapability(MediaControlCapabilitySupport support)
597         {
598             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
599
600             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Shuffle, support).
601                 ThrowIfError("Failed to set shuffle mode capability.");
602         }
603
604         /// <summary>
605         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating repeat mode is supported or not.
606         /// </summary>
607         /// <param name="support">A value indicating whether the <see cref="MediaControlRepeatMode"/> is supported or not.</param>
608         /// <exception cref="InvalidOperationException">
609         ///     The server is not running .<br/>
610         ///     -or-<br/>
611         ///     An internal error occurs.
612         /// </exception>
613         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
614         /// <since_tizen> 5 </since_tizen>
615         public static void SetRepeatModeCapability(MediaControlCapabilitySupport support)
616         {
617             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
618
619             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Repeat, support).
620                 ThrowIfError("Failed to set repeat mode capability.");
621         }
622
623         /// <summary>
624         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating whether 360 mode is supported or not.
625         /// </summary>
626         /// <param name="support">A value indicating whether the 360 mode is supported or not.</param>
627         /// <exception cref="InvalidOperationException">
628         ///     The server is not running .<br/>
629         ///     -or-<br/>
630         ///     An internal error occurs.
631         /// </exception>
632         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
633         /// <since_tizen> 6 </since_tizen>
634         public static void SetMode360Capability(MediaControlCapabilitySupport support)
635         {
636             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
637
638             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Mode360, support).
639                 ThrowIfError("Failed to set 360 mode capability.");
640         }
641
642         /// <summary>
643         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating whether subtitle mode is supported or not.
644         /// </summary>
645         /// <param name="support">A value indicating whether the subtitle mode is supported or not.</param>
646         /// <exception cref="InvalidOperationException">
647         ///     The server is not running .<br/>
648         ///     -or-<br/>
649         ///     An internal error occurs.
650         /// </exception>
651         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
652         /// <since_tizen> 6 </since_tizen>
653         public static void SetSubtitleModeCapability(MediaControlCapabilitySupport support)
654         {
655             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
656
657             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Subtitle, support).
658                 ThrowIfError("Failed to set subtitle mode capability.");
659         }
660
661         /// <summary>
662         /// Sets the supported list of <see cref="MediaControlDisplayMode"/>.
663         /// </summary>
664         /// <remarks>
665         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.
666         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
667         /// </remarks>
668         /// <param name="capabilities">The supported list of <see cref="MediaControlDisplayMode"/>.</param>
669         /// <exception cref="InvalidOperationException">
670         ///     The server is not running .<br/>
671         ///     -or-<br/>
672         ///     An internal error occurs.
673         /// </exception>
674         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
675         /// <since_tizen> 6 </since_tizen>
676         public static void SetDisplayModeCapabilities(IDictionary<MediaControlDisplayMode, MediaControlCapabilitySupport> capabilities)
677         {
678             foreach (var pair in capabilities)
679             {
680                 SetDisplayModeCapability(pair.Key, pair.Value);
681             }
682         }
683
684         /// <summary>
685         /// Sets the <paramref name="mode"/> is supported or not.
686         /// </summary>
687         /// <remarks>
688         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.<br/>
689         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
690         /// </remarks>
691         /// <param name="mode">The <see cref="MediaControlDisplayMode"/>.</param>
692         /// <param name="support">A value indicating whether the <paramref name="mode"/> is supported or not.</param>
693         /// <exception cref="InvalidOperationException">
694         ///     The server is not running .<br/>
695         ///     -or-<br/>
696         ///     An internal error occurs.
697         /// </exception>
698         /// <exception cref="ArgumentException"><paramref name="mode"/> or <paramref name="support"/> is invalid.</exception>
699         /// <since_tizen> 6 </since_tizen>
700         public static void SetDisplayModeCapability(MediaControlDisplayMode mode, MediaControlCapabilitySupport support)
701         {
702             ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
703             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
704
705             if (support == MediaControlCapabilitySupport.NotDecided)
706             {
707                 throw new ArgumentException($"NotDecided is not allowed in {mode} capability.");
708             }
709
710             Native.SetDisplayModeCapability(Handle, (uint)mode.ToNative(), support).
711                 ThrowIfError("Failed to set display mode capability.");
712         }
713
714         /// <summary>
715         /// Sets the supported list of <see cref="Rotation"/>.
716         /// </summary>
717         /// <remarks>
718         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
719         /// The default value of each <see cref="Rotation"/> is not supported.
720         /// </remarks>
721         /// <param name="capabilities">The supported list of <see cref="Rotation"/>.</param>
722         /// <exception cref="InvalidOperationException">
723         ///     The server is not running .<br/>
724         ///     -or-<br/>
725         ///     An internal error occurs.
726         /// </exception>
727         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
728         /// <since_tizen> 6 </since_tizen>
729         public static void SetDisplayRotationCapabilities(IDictionary<Rotation, MediaControlCapabilitySupport> capabilities)
730         {
731             foreach (var pair in capabilities)
732             {
733                 SetDisplayRotationCapability(pair.Key, pair.Value);
734             }
735         }
736
737         /// <summary>
738         /// Sets the <paramref name="rotation"/> is supported or not.
739         /// </summary>
740         /// <remarks>
741         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
742         /// The default value of each <see cref="Rotation"/> is not supported.
743         /// </remarks>
744         /// <param name="rotation">The <see cref="Rotation"/>.</param>
745         /// <param name="support">A value indicating whether the <paramref name="rotation"/> is supported or not..</param>
746         /// <exception cref="InvalidOperationException">
747         ///     The server is not running .<br/>
748         ///     -or-<br/>
749         ///     An internal error occurs.
750         /// </exception>
751         /// <exception cref="ArgumentException"><paramref name="rotation"/> or <paramref name="support"/> is invalid.</exception>
752         /// <since_tizen> 6 </since_tizen>
753         public static void SetDisplayRotationCapability(Rotation rotation, MediaControlCapabilitySupport support)
754         {
755             ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
756             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
757
758             if (support == MediaControlCapabilitySupport.NotDecided)
759             {
760                 throw new ArgumentException($"NotDecided is not allowed in {rotation} capability.");
761             }
762
763             Native.SetDisplayRotationCapability(Handle, (uint)rotation.ToNative(), support).
764                 ThrowIfError("Failed to set display rotation capability.");
765         }
766         #endregion Capability
767
768
769         #region Command
770         /// <summary>
771         /// Requests commands to the client.
772         /// </summary>
773         /// <remarks>
774         /// The client can request the command to execute <see cref="Command"/>, <br/>
775         /// and then, the server receive the result of each request(command).
776         /// </remarks>
777         /// <param name="command">A <see cref="Command"/> class.</param>
778         /// <param name="clientId">The client Id to send command.</param>
779         /// <returns><see cref="Bundle"/> represents the extra data from client and it can be null.</returns>
780         /// <exception cref="ArgumentNullException">
781         /// <paramref name="command"/> or <paramref name="clientId"/> is null.
782         /// </exception>
783         /// <exception cref="InvalidOperationException">
784         ///     The server has already been stopped.<br/>
785         ///     -or-<br/>
786         ///     An internal error occurs.
787         /// </exception>
788         /// <since_tizen> 5 </since_tizen>
789         public static async Task<Bundle> RequestAsync(Command command, string clientId)
790         {
791             if (command == null)
792             {
793                 throw new ArgumentNullException(nameof(command));
794             }
795             if (clientId == null)
796             {
797                 throw new ArgumentNullException(nameof(clientId));
798             }
799
800             command.SetRequestInformation(clientId);
801
802             var tcs = new TaskCompletionSource<MediaControllerError>();
803             string reqeustId = null;
804             Bundle bundle = null;
805
806             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
807             {
808                 if (e.RequestId == reqeustId)
809                 {
810                     bundle = e.Bundle;
811                     tcs.TrySetResult(e.Result);
812                 }
813             };
814
815             try
816             {
817                 CommandCompleted += eventHandler;
818
819                 reqeustId = command.Request(Handle);
820
821                 (await tcs.Task).ThrowIfError("Failed to request event.");
822
823                 return bundle;
824             }
825             finally
826             {
827                 CommandCompleted -= eventHandler;
828             }
829         }
830
831         /// <summary>
832         /// Sends the result of each command.
833         /// </summary>
834         /// <param name="command">The command that return to client.</param>
835         /// <param name="result">The result of <paramref name="command"/>.</param>
836         /// <param name="bundle">The extra data.</param>
837         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
838         /// <exception cref="InvalidOperationException">
839         ///     The server is not running .<br/>
840         ///     -or-<br/>
841         ///     An internal error occurs.
842         /// </exception>
843         /// <since_tizen> 5 </since_tizen>
844         public static void Response(Command command, int result, Bundle bundle)
845         {
846             if (command == null)
847             {
848                 throw new ArgumentNullException(nameof(command));
849             }
850
851             command.Response(Handle, result, bundle);
852         }
853
854         /// <summary>
855         /// Sends the result of each command.
856         /// </summary>
857         /// <param name="command">The command that return to client.</param>
858         /// <param name="result">The result of <paramref name="command"/>.</param>
859         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
860         /// <exception cref="InvalidOperationException">
861         ///     The server is not running .<br/>
862         ///     -or-<br/>
863         ///     An internal error occurs.
864         /// </exception>
865         /// <since_tizen> 5 </since_tizen>
866         public static void Response(Command command, int result)
867         {
868             if (command == null)
869             {
870                 throw new ArgumentNullException(nameof(command));
871             }
872
873             command.Response(Handle, result, null);
874         }
875         #endregion Command
876     }
877 }