Release 8.0.0.15812
[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                 _handle = IntPtr.Zero;
130                 _serverName = null;
131                 throw;
132             }
133         }
134
135         /// <summary>
136         /// Starts the media control server.
137         /// </summary>
138         /// <remarks>
139         /// When the server starts, <see cref="MediaControllerManager.ServerStarted"/> will be raised.
140         /// </remarks>
141         /// <privilege>http://tizen.org/privilege/mediacontroller.server</privilege>
142         /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
143         /// <exception cref="UnauthorizedAccessException">Caller does not have required privilege.</exception>
144         /// <seealso cref="MediaControllerManager.ServerStarted"/>
145         /// <since_tizen> 4 </since_tizen>
146         public static void Start()
147         {
148             Initialize();
149         }
150
151         /// <summary>
152         /// Stops the media control server.
153         /// </summary>
154         /// <remarks>
155         /// When the server stops, <see cref="MediaControllerManager.ServerStopped"/> will be raised.
156         /// </remarks>
157         /// <exception cref="InvalidOperationException">
158         ///     The server is not running .<br/>
159         ///     -or-<br/>
160         ///     An internal error occurs.
161         /// </exception>
162         /// <seealso cref="MediaControllerManager.ServerStopped"/>
163         /// <since_tizen> 4 </since_tizen>
164         public static void Stop()
165         {
166             EnsureInitializedIfRunning();
167
168             Native.Destroy(_handle).ThrowIfError("Failed to stop the server.");
169
170             _handle = IntPtr.Zero;
171             _isRunning = false;
172         }
173
174         /// <summary>
175         /// Gets the active clients.
176         /// </summary>
177         /// <exception cref="InvalidOperationException">
178         ///     The server is not running .<br/>
179         ///     -or-<br/>
180         ///     An internal error occurs.
181         /// </exception>
182         /// <returns>the activated client ids.</returns>
183         /// <since_tizen> 5 </since_tizen>
184         public static IEnumerable<string> GetActivatedClients()
185         {
186             var clientIds = new List<string>();
187
188             Native.ActivatedClientCallback activatedClientCallback = (name, _) =>
189             {
190                 clientIds.Add(name);
191                 return true;
192             };
193
194             Native.ForeachActivatedClient(Handle, activatedClientCallback).
195                 ThrowIfError("Failed to get activated client.");
196
197             return clientIds.AsReadOnly();
198         }
199
200
201         #region Set information
202         /// <summary>
203         /// Updates playback state and playback position.</summary>
204         /// <param name="state">The playback state.</param>
205         /// <param name="position">The playback position in milliseconds.</param>
206         /// <exception cref="ArgumentException"><paramref name="state"/> is not valid.</exception>
207         /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero.</exception>
208         /// <exception cref="InvalidOperationException">
209         ///     The server is not running .<br/>
210         ///     -or-<br/>
211         ///     An internal error occurs.
212         /// </exception>
213         /// <since_tizen> 4 </since_tizen>
214         public static void SetPlaybackState(MediaControlPlaybackState state, long position)
215         {
216             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackState), state, nameof(state));
217
218             if (position < 0)
219             {
220                 throw new ArgumentOutOfRangeException(nameof(position), position, "position can't be less than zero.");
221             }
222
223             Native.SetPlaybackState(Handle, state.ToNative()).ThrowIfError("Failed to set playback state.");
224
225             Native.SetPlaybackPosition(Handle, (ulong)position).ThrowIfError("Failed to set playback position.");
226
227             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
228         }
229
230         private static void SetMetadata(MediaControllerNativeAttribute attribute, string value)
231         {
232             if (value != null)
233             {
234                 Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
235             }
236         }
237
238         /// <summary>
239         /// Updates metadata information.
240         /// </summary>
241         /// <param name="metadata">The metadata to update.</param>
242         /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception>
243         /// <exception cref="InvalidOperationException">
244         ///     The server is not running .<br/>
245         ///     -or-<br/>
246         ///     An internal error occurs.
247         /// </exception>
248         /// <since_tizen> 4 </since_tizen>
249         public static void SetMetadata(MediaControlMetadata metadata)
250         {
251             if (metadata == null)
252             {
253                 throw new ArgumentNullException(nameof(metadata));
254             }
255
256             SetMetadata(MediaControllerNativeAttribute.Title, metadata.Title);
257             SetMetadata(MediaControllerNativeAttribute.Artist, metadata.Artist);
258             SetMetadata(MediaControllerNativeAttribute.Album, metadata.Album);
259             SetMetadata(MediaControllerNativeAttribute.Author, metadata.Author);
260             SetMetadata(MediaControllerNativeAttribute.Genre, metadata.Genre);
261             SetMetadata(MediaControllerNativeAttribute.Duration, metadata.Duration);
262             SetMetadata(MediaControllerNativeAttribute.Date, metadata.Date);
263             SetMetadata(MediaControllerNativeAttribute.Copyright, metadata.Copyright);
264             SetMetadata(MediaControllerNativeAttribute.Description, metadata.Description);
265             SetMetadata(MediaControllerNativeAttribute.TrackNumber, metadata.TrackNumber);
266             SetMetadata(MediaControllerNativeAttribute.Picture, metadata.AlbumArtPath);
267             SetMetadata(MediaControllerNativeAttribute.Season, metadata.EncodedSeason);
268             SetMetadata(MediaControllerNativeAttribute.Episode, metadata.EncodedEpisode);
269             SetMetadata(MediaControllerNativeAttribute.Resolution, metadata.EncodedResolution);
270
271             Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
272         }
273
274         /// <summary>
275         /// Updates the shuffle mode.
276         /// </summary>
277         /// <param name="enabled">A value indicating whether the shuffle mode is enabled.</param>
278         /// <exception cref="InvalidOperationException">
279         ///     The server is not running .<br/>
280         ///     -or-<br/>
281         ///     An internal error occurs.
282         /// </exception>
283         /// <since_tizen> 4 </since_tizen>
284         public static void SetShuffleModeEnabled(bool enabled)
285         {
286             Native.UpdateShuffleMode(Handle, enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off).
287                 ThrowIfError("Failed to set shuffle mode.");
288         }
289
290         /// <summary>
291         /// Updates the repeat mode.
292         /// </summary>
293         /// <param name="mode">A value indicating the repeat mode.</param>
294         /// <exception cref="InvalidOperationException">
295         ///     The server is not running .<br/>
296         ///     -or-<br/>
297         ///     An internal error occurs.
298         /// </exception>
299         /// <exception cref="ArgumentException"><paramref name="mode"/> is invalid.</exception>
300         /// <since_tizen> 4 </since_tizen>
301         public static void SetRepeatMode(MediaControlRepeatMode mode)
302         {
303             ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
304
305             Native.UpdateRepeatMode(Handle, mode.ToNative()).ThrowIfError("Failed to set repeat mode.");
306         }
307
308         /// <summary>
309         /// Sets the playlist name and index of current playing media.
310         /// </summary>
311         /// <param name="playlistName">The playlist name of current playing media.</param>
312         /// <param name="index">The index of current playing media.</param>
313         /// <exception cref="ArgumentNullException">
314         /// <paramref name="playlistName"/> or <paramref name="index"/> is null.
315         /// </exception>
316         /// <exception cref="InvalidOperationException">
317         ///     The server is not running .<br/>
318         ///     -or-<br/>
319         ///     An internal error occurs.
320         /// </exception>
321         /// <since_tizen> 5 </since_tizen>
322         public static void SetInfoOfCurrentPlayingMedia(string playlistName, string index)
323         {
324             if (playlistName == null)
325             {
326                 throw new ArgumentNullException(nameof(playlistName));
327             }
328             if (index == null)
329             {
330                 throw new ArgumentNullException(nameof(index));
331             }
332
333             Native.SetInfoOfCurrentPlayingMedia(Handle, playlistName, index)
334                 .ThrowIfError("Failed to set the playlist name and index of current playing media");
335
336             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
337         }
338
339         /// <summary>
340         /// Sets the age rating of latest played media.
341         /// </summary>
342         /// <param name="ageRating">
343         /// The Age rating of latest played media. The valid range is 0 to 19, inclusive.
344         /// Especially, 0 means that media is suitable for all ages.
345         /// </param>
346         /// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="ageRating"/> is not valid.</exception>
347         /// <exception cref="InvalidOperationException">
348         ///     The server is not running .<br/>
349         ///     -or-<br/>
350         ///     An internal error occurs.
351         /// </exception>
352         /// <since_tizen> 5 </since_tizen>
353         public static void SetAgeRating(int ageRating)
354         {
355             if (ageRating < 0 || ageRating > 19)
356             {
357                 throw new ArgumentOutOfRangeException(nameof(ageRating));
358             }
359
360             Native.SetAgeRating(Handle, ageRating).ThrowIfError("Failed to set age rating.");
361
362             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
363         }
364
365         /// <summary>
366         /// Sets the subtitle mode.
367         /// </summary>
368         /// <param name="isEnabled">A value indicating whether the subtitle mode is enabled.</param>
369         /// <exception cref="InvalidOperationException">
370         ///     The server is not running .<br/>
371         ///     -or-<br/>
372         ///     An internal error occurs.
373         /// </exception>
374         /// <since_tizen> 6 </since_tizen>
375         public static void SetSubtitleMode(bool isEnabled)
376         {
377             Native.UpdateSubtitleMode(Handle, isEnabled).ThrowIfError("Failed to set subtitle mode.");
378         }
379
380         /// <summary>
381         /// Sets the 360 mode.
382         /// </summary>
383         /// <param name="isEnabled">A value indicating whether the 360 mode is enabled.</param>
384         /// <exception cref="InvalidOperationException">
385         ///     The server is not running .<br/>
386         ///     -or-<br/>
387         ///     An internal error occurs.
388         /// </exception>
389         /// <since_tizen> 6 </since_tizen>
390         public static void SetMode360(bool isEnabled)
391         {
392             Native.UpdateMode360(Handle, isEnabled).ThrowIfError("Failed to set 360 mode.");
393         }
394
395         /// <summary>
396         /// Sets the display mode.
397         /// </summary>
398         /// <param name="mode">A value indicating the <see cref="MediaControlDisplayMode"/>.</param>
399         /// <exception cref="InvalidOperationException">
400         ///     The server is not running .<br/>
401         ///     -or-<br/>
402         ///     An internal error occurs.
403         /// </exception>
404         /// <since_tizen> 6 </since_tizen>
405         public static void SetDisplayMode(MediaControlDisplayMode mode)
406         {
407             Native.UpdateDisplayMode(Handle, mode.ToNative()).ThrowIfError("Failed to set display mode.");
408         }
409
410         /// <summary>
411         /// Sets the display rotation.
412         /// </summary>
413         /// <param name="rotation">A value indicating the <see cref="Rotation"/>.</param>
414         /// <exception cref="InvalidOperationException">
415         ///     The server is not running .<br/>
416         ///     -or-<br/>
417         ///     An internal error occurs.
418         /// </exception>
419         /// <since_tizen> 6 </since_tizen>
420         public static void SetDisplayRotation(Rotation rotation)
421         {
422             Native.UpdateDisplayRotaton(Handle, rotation.ToNative()).ThrowIfError("Failed to set display rotation.");
423         }
424
425         /// <summary>
426         /// Sets the index of current playing media.
427         /// </summary>
428         /// <param name="index">The index of current playing media.</param>
429         /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
430         /// <exception cref="InvalidOperationException">
431         ///     The server is not running .<br/>
432         ///     -or-<br/>
433         ///     An internal error occurs.
434         /// </exception>
435         /// <since_tizen> 5 </since_tizen>
436         [Obsolete("Please do not use! This will be deprecated. Please use SetInfoOfCurrentPlayingMedia instead.")]
437         public static void SetIndexOfCurrentPlayingMedia(string index)
438         {
439             if (index == null)
440             {
441                 throw new ArgumentNullException(nameof(index));
442             }
443
444             Native.SetIndexOfCurrentPlayingMedia(Handle, index)
445                 .ThrowIfError("Failed to set the index of current playing media");
446
447             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
448         }
449         #endregion Set information
450
451
452         #region Playlist
453         /// <summary>
454         /// Delete playlist.
455         /// </summary>
456         /// <remarks>Currently, only server can remove the playlist.</remarks>
457         /// <param name="playlist">The name of playlist.</param>
458         /// <exception cref="ArgumentNullException"><paramref name="playlist"/> is null.</exception>
459         /// <exception cref="InvalidOperationException">
460         ///     The server is not running .<br/>
461         ///     -or-<br/>
462         ///     An internal error occurs.
463         /// </exception>
464         /// <since_tizen> 5 </since_tizen>
465         public static void RemovePlaylist(MediaControlPlaylist playlist)
466         {
467             if (playlist == null)
468             {
469                 throw new ArgumentNullException(nameof(playlist));
470             }
471
472             Native.DeletePlaylist(Handle, playlist.Handle);
473             playlist.Dispose();
474         }
475
476         // Saves the playlist to the persistent storage.
477         internal static void SavePlaylist(IntPtr playlistHandle)
478         {
479             Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
480         }
481
482         // Gets the playlist handle by name.
483         internal static IntPtr GetPlaylistHandle(string name)
484         {
485             NativePlaylist.GetPlaylistHandle(_serverName, name, out IntPtr playlistHandle).
486                 ThrowIfError("Failed to get playlist handle by name");
487
488             return playlistHandle;
489         }
490         #endregion Playlist
491
492
493         #region Capability
494         /// <summary>
495         /// Sets the content type of latest played media.
496         /// </summary>
497         /// <param name="type">A value indicating the content type of the latest played media.</param>
498         /// <exception cref="InvalidOperationException">
499         ///     The server is not running .<br/>
500         ///     -or-<br/>
501         ///     An internal error occurs.
502         /// </exception>
503         /// <exception cref="ArgumentException"><paramref name="type"/> is invalid.</exception>
504         /// <since_tizen> 5 </since_tizen>
505         public static void SetPlaybackContentType(MediaControlContentType type)
506         {
507             ValidationUtil.ValidateEnum(typeof(MediaControlContentType), type, nameof(type));
508
509             Native.SetPlaybackContentType(Handle, type).ThrowIfError("Failed to set playback content type.");
510
511             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
512         }
513
514         /// <summary>
515         /// Sets the path of icon.
516         /// </summary>
517         /// <param name="path">The path of icon.</param>
518         /// <exception cref="InvalidOperationException">
519         ///     The server is not running .<br/>
520         ///     -or-<br/>
521         ///     An internal error occurs.
522         /// </exception>
523         /// <exception cref="ArgumentNullException"><paramref name="path"/> is invalid.</exception>
524         /// <since_tizen> 5 </since_tizen>
525         public static void SetIconPath(string path)
526         {
527             if (path == null)
528             {
529                 throw new ArgumentNullException(nameof(path));
530             }
531
532             Native.SetIconPath(Handle, path).ThrowIfError("Failed to set uri path.");
533         }
534
535         /// <summary>
536         /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
537         /// </summary>
538         /// <param name="capabilities">The set of <see cref="MediaControlPlaybackCommand"/> and <see cref="MediaControlCapabilitySupport"/>.</param>
539         /// <exception cref="InvalidOperationException">
540         ///     The server is not running .<br/>
541         ///     -or-<br/>
542         ///     An internal error occurs.
543         /// </exception>
544         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
545         /// <since_tizen> 5 </since_tizen>
546         public static void SetPlaybackCapabilities(Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport> capabilities)
547         {
548             foreach (var pair in capabilities)
549             {
550                 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), pair.Key, nameof(pair.Key));
551                 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), pair.Value, nameof(pair.Value));
552
553                 SetPlaybackCapability(pair.Key, pair.Value);
554                 Native.SetPlaybackCapability(Handle, pair.Key.ToNative(), pair.Value).
555                     ThrowIfError("Failed to set playback capability.");
556             }
557
558             Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
559         }
560
561         /// <summary>
562         /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
563         /// </summary>
564         /// <param name="action">A playback command.</param>
565         /// <param name="support">A value indicating whether the <paramref name="action"/> is supported or not.</param>
566         /// <exception cref="InvalidOperationException">
567         ///     The server is not running .<br/>
568         ///     -or-<br/>
569         ///     An internal error occurs.
570         /// </exception>
571         /// <exception cref="ArgumentException"><paramref name="action"/> or <paramref name="support"/> is invalid.</exception>
572         /// <since_tizen> 5 </since_tizen>
573         public static void SetPlaybackCapability(MediaControlPlaybackCommand action, MediaControlCapabilitySupport support)
574         {
575             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
576             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
577
578             Native.SetPlaybackCapability(Handle, action.ToNative(), support).ThrowIfError("Failed to set playback capability.");
579
580             Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
581         }
582
583         /// <summary>
584         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating shuffle mode is supported or not.
585         /// </summary>
586         /// <param name="support">A value indicating whether the shuffle mode is supported or not.</param>
587         /// <exception cref="InvalidOperationException">
588         ///     The server is not running .<br/>
589         ///     -or-<br/>
590         ///     An internal error occurs.
591         /// </exception>
592         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
593         /// <since_tizen> 5 </since_tizen>
594         public static void SetShuffleModeCapability(MediaControlCapabilitySupport support)
595         {
596             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
597
598             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Shuffle, support).
599                 ThrowIfError("Failed to set shuffle mode capability.");
600         }
601
602         /// <summary>
603         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating repeat mode is supported or not.
604         /// </summary>
605         /// <param name="support">A value indicating whether the <see cref="MediaControlRepeatMode"/> is supported or not.</param>
606         /// <exception cref="InvalidOperationException">
607         ///     The server is not running .<br/>
608         ///     -or-<br/>
609         ///     An internal error occurs.
610         /// </exception>
611         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
612         /// <since_tizen> 5 </since_tizen>
613         public static void SetRepeatModeCapability(MediaControlCapabilitySupport support)
614         {
615             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
616
617             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Repeat, support).
618                 ThrowIfError("Failed to set repeat mode capability.");
619         }
620
621         /// <summary>
622         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating whether 360 mode is supported or not.
623         /// </summary>
624         /// <param name="support">A value indicating whether the 360 mode is supported or not.</param>
625         /// <exception cref="InvalidOperationException">
626         ///     The server is not running .<br/>
627         ///     -or-<br/>
628         ///     An internal error occurs.
629         /// </exception>
630         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
631         /// <since_tizen> 6 </since_tizen>
632         public static void SetMode360Capability(MediaControlCapabilitySupport support)
633         {
634             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
635
636             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Mode360, support).
637                 ThrowIfError("Failed to set 360 mode capability.");
638         }
639
640         /// <summary>
641         /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating whether subtitle mode is supported or not.
642         /// </summary>
643         /// <param name="support">A value indicating whether the subtitle mode is supported or not.</param>
644         /// <exception cref="InvalidOperationException">
645         ///     The server is not running .<br/>
646         ///     -or-<br/>
647         ///     An internal error occurs.
648         /// </exception>
649         /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
650         /// <since_tizen> 6 </since_tizen>
651         public static void SetSubtitleModeCapability(MediaControlCapabilitySupport support)
652         {
653             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
654
655             Native.SetSimpleCapability(Handle, MediaControlNativeCapabilityCategory.Subtitle, support).
656                 ThrowIfError("Failed to set subtitle mode capability.");
657         }
658
659         /// <summary>
660         /// Sets the supported list of <see cref="MediaControlDisplayMode"/>.
661         /// </summary>
662         /// <remarks>
663         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.
664         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
665         /// </remarks>
666         /// <param name="capabilities">The supported list of <see cref="MediaControlDisplayMode"/>.</param>
667         /// <exception cref="InvalidOperationException">
668         ///     The server is not running .<br/>
669         ///     -or-<br/>
670         ///     An internal error occurs.
671         /// </exception>
672         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
673         /// <since_tizen> 6 </since_tizen>
674         public static void SetDisplayModeCapabilities(IDictionary<MediaControlDisplayMode, MediaControlCapabilitySupport> capabilities)
675         {
676             foreach (var pair in capabilities)
677             {
678                 SetDisplayModeCapability(pair.Key, pair.Value);
679             }
680         }
681
682         /// <summary>
683         /// Sets the <paramref name="mode"/> is supported or not.
684         /// </summary>
685         /// <remarks>
686         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.<br/>
687         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
688         /// </remarks>
689         /// <param name="mode">The <see cref="MediaControlDisplayMode"/>.</param>
690         /// <param name="support">A value indicating whether the <paramref name="mode"/> is supported or not.</param>
691         /// <exception cref="InvalidOperationException">
692         ///     The server is not running .<br/>
693         ///     -or-<br/>
694         ///     An internal error occurs.
695         /// </exception>
696         /// <exception cref="ArgumentException"><paramref name="mode"/> or <paramref name="support"/> is invalid.</exception>
697         /// <since_tizen> 6 </since_tizen>
698         public static void SetDisplayModeCapability(MediaControlDisplayMode mode, MediaControlCapabilitySupport support)
699         {
700             ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
701             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
702
703             if (support == MediaControlCapabilitySupport.NotDecided)
704             {
705                 throw new ArgumentException($"NotDecided is not allowed in {mode} capability.");
706             }
707
708             Native.SetDisplayModeCapability(Handle, (uint)mode.ToNative(), support).
709                 ThrowIfError("Failed to set display mode capability.");
710         }
711
712         /// <summary>
713         /// Sets the supported list of <see cref="Rotation"/>.
714         /// </summary>
715         /// <remarks>
716         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
717         /// The default value of each <see cref="Rotation"/> is not supported.
718         /// </remarks>
719         /// <param name="capabilities">The supported list of <see cref="Rotation"/>.</param>
720         /// <exception cref="InvalidOperationException">
721         ///     The server is not running .<br/>
722         ///     -or-<br/>
723         ///     An internal error occurs.
724         /// </exception>
725         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
726         /// <since_tizen> 6 </since_tizen>
727         public static void SetDisplayRotationCapabilities(IDictionary<Rotation, MediaControlCapabilitySupport> capabilities)
728         {
729             foreach (var pair in capabilities)
730             {
731                 SetDisplayRotationCapability(pair.Key, pair.Value);
732             }
733         }
734
735         /// <summary>
736         /// Sets the <paramref name="rotation"/> is supported or not.
737         /// </summary>
738         /// <remarks>
739         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
740         /// The default value of each <see cref="Rotation"/> is not supported.
741         /// </remarks>
742         /// <param name="rotation">The <see cref="Rotation"/>.</param>
743         /// <param name="support">A value indicating whether the <paramref name="rotation"/> is supported or not..</param>
744         /// <exception cref="InvalidOperationException">
745         ///     The server is not running .<br/>
746         ///     -or-<br/>
747         ///     An internal error occurs.
748         /// </exception>
749         /// <exception cref="ArgumentException"><paramref name="rotation"/> or <paramref name="support"/> is invalid.</exception>
750         /// <since_tizen> 6 </since_tizen>
751         public static void SetDisplayRotationCapability(Rotation rotation, MediaControlCapabilitySupport support)
752         {
753             ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
754             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
755
756             if (support == MediaControlCapabilitySupport.NotDecided)
757             {
758                 throw new ArgumentException($"NotDecided is not allowed in {rotation} capability.");
759             }
760
761             Native.SetDisplayRotationCapability(Handle, (uint)rotation.ToNative(), support).
762                 ThrowIfError("Failed to set display rotation capability.");
763         }
764         #endregion Capability
765
766
767         #region Command
768         /// <summary>
769         /// Requests a command to the client and server receives the result of each request(command).
770         /// </summary>
771         /// <param name="command">A <see cref="Command"/> class.</param>
772         /// <param name="clientId">The client Id to send command.</param>
773         /// <returns>
774         /// The type of return value is Tuple.<br/>
775         /// First item of Tuple represents the <see cref="Bundle"/> and it represents the extra data from client. It can be null.<br/>
776         /// Second item of Tuple represents the result of each request(command).
777         /// </returns>
778         /// <exception cref="ArgumentNullException">
779         /// <paramref name="command"/> or <paramref name="clientId"/> is null.
780         /// </exception>
781         /// <exception cref="InvalidOperationException">
782         ///     The server has already been stopped.<br/>
783         ///     -or-<br/>
784         ///     An internal error occurs.
785         /// </exception>
786         /// <exception cref="NotImplementedException">The command which is not supported is used.</exception>
787         /// <seealso cref="CustomCommand"/>
788         /// <since_tizen> 8 </since_tizen>
789         public static async Task<(Bundle bundle, int result)> RequestCommandAsync(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<int>();
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                 var result = await tcs.Task;
822
823                 return (bundle, result);
824             }
825             finally
826             {
827                 CommandCompleted -= eventHandler;
828             }
829         }
830
831         /// <summary>
832         /// Requests commands to the client.
833         /// </summary>
834         /// <param name="command">A <see cref="Command"/> class.</param>
835         /// <param name="clientId">The client Id to send command.</param>
836         /// <returns><see cref="Bundle"/> represents the extra data from client and it can be null.</returns>
837         /// <exception cref="ArgumentNullException">
838         /// <paramref name="command"/> or <paramref name="clientId"/> is null.
839         /// </exception>
840         /// <exception cref="InvalidOperationException">
841         ///     The server has already been stopped.<br/>
842         ///     -or-<br/>
843         ///     An internal error occurs.
844         /// </exception>
845         /// <seealso cref="CustomCommand"/>
846         /// <since_tizen> 5 </since_tizen>
847         [Obsolete("Deprecated since API8; Will be removed in API10. Please use RequestCommandAsync(Command command) instead.")]
848         public static async Task<Bundle> RequestAsync(Command command, string clientId)
849         {
850             if (command == null)
851             {
852                 throw new ArgumentNullException(nameof(command));
853             }
854             if (clientId == null)
855             {
856                 throw new ArgumentNullException(nameof(clientId));
857             }
858
859             command.SetRequestInformation(clientId);
860
861             var tcs = new TaskCompletionSource<int>();
862             string reqeustId = null;
863             Bundle bundle = null;
864
865             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
866             {
867                 if (e.RequestId == reqeustId)
868                 {
869                     bundle = e.Bundle;
870                     tcs.TrySetResult(e.Result);
871                 }
872             };
873
874             try
875             {
876                 CommandCompleted += eventHandler;
877
878                 reqeustId = command.Request(Handle);
879
880                 ((MediaControllerError)await tcs.Task).ThrowIfError("Failed to request event.");
881
882                 return bundle;
883             }
884             finally
885             {
886                 CommandCompleted -= eventHandler;
887             }
888         }
889
890         /// <summary>
891         /// Sends the result of each command.
892         /// </summary>
893         /// <param name="command">The command that return to client.</param>
894         /// <param name="result">The result of <paramref name="command"/>.</param>
895         /// <param name="bundle">The extra data.</param>
896         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
897         /// <exception cref="InvalidOperationException">
898         ///     The server is not running .<br/>
899         ///     -or-<br/>
900         ///     An internal error occurs.
901         /// </exception>
902         /// <since_tizen> 5 </since_tizen>
903         public static void Response(Command command, int result, Bundle bundle)
904         {
905             if (command == null)
906             {
907                 throw new ArgumentNullException(nameof(command));
908             }
909
910             command.Response(Handle, result, bundle);
911         }
912
913         /// <summary>
914         /// Sends the result of each command.
915         /// </summary>
916         /// <param name="command">The command that return to client.</param>
917         /// <param name="result">The result of <paramref name="command"/>.</param>
918         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
919         /// <exception cref="InvalidOperationException">
920         ///     The server is not running .<br/>
921         ///     -or-<br/>
922         ///     An internal error occurs.
923         /// </exception>
924         /// <since_tizen> 5 </since_tizen>
925         public static void Response(Command command, int result)
926         {
927             Response(command, result, null);
928         }
929
930         /// <summary>
931         /// Sends the result of each command.
932         /// </summary>
933         /// <param name="command">The command that return to client.</param>
934         /// <param name="result">The <see cref="MediaControlResult"/> of <paramref name="command"/>.</param>
935         /// <param name="bundle">The extra data.</param>
936         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
937         /// <exception cref="InvalidOperationException">
938         ///     The server is not running .<br/>
939         ///     -or-<br/>
940         ///     An internal error occurs.
941         /// </exception>
942         /// <since_tizen> 8 </since_tizen>
943         public static void Response(Command command, MediaControlResult result, Bundle bundle)
944         {
945             Response(command, (int)result, bundle);
946         }
947
948         /// <summary>
949         /// Sends the result of each command.
950         /// </summary>
951         /// <param name="command">The command that return to client.</param>
952         /// <param name="result">The <see cref="MediaControlResult"/> of <paramref name="command"/>.</param>
953         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
954         /// <exception cref="InvalidOperationException">
955         ///     The server is not running .<br/>
956         ///     -or-<br/>
957         ///     An internal error occurs.
958         /// </exception>
959         /// <since_tizen> 8 </since_tizen>
960         public static void Response(Command command, MediaControlResult result)
961         {
962             Response(command, (int)result, null);
963         }
964         #endregion Command
965     }
966 }