4b788b80c57a7dc547dffddef1cf9a04abd84e39
[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 supported list of <see cref="MediaControlDisplayMode"/>.
625         /// </summary>
626         /// <remarks>
627         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.
628         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
629         /// </remarks>
630         /// <param name="capabilities">The supported list of <see cref="MediaControlDisplayMode"/>.</param>
631         /// <exception cref="InvalidOperationException">
632         ///     The server is not running .<br/>
633         ///     -or-<br/>
634         ///     An internal error occurs.
635         /// </exception>
636         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
637         /// <since_tizen> 6 </since_tizen>
638         public static void SetDisplayModeCapabilities(IDictionary<MediaControlDisplayMode, MediaControlCapabilitySupport> capabilities)
639         {
640             foreach (var pair in capabilities)
641             {
642                 SetDisplayModeCapability(pair.Key, pair.Value);
643             }
644         }
645
646         /// <summary>
647         /// Sets the <paramref name="mode"/> is supported or not.
648         /// </summary>
649         /// <remarks>
650         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display mode capability.<br/>
651         /// The default value of each <see cref="MediaControlDisplayMode"/> is not supported.
652         /// </remarks>
653         /// <param name="mode">The <see cref="MediaControlDisplayMode"/>.</param>
654         /// <param name="support">A value indicating whether the <paramref name="mode"/> is supported or not.</param>
655         /// <exception cref="InvalidOperationException">
656         ///     The server is not running .<br/>
657         ///     -or-<br/>
658         ///     An internal error occurs.
659         /// </exception>
660         /// <exception cref="ArgumentException"><paramref name="mode"/> or <paramref name="support"/> is invalid.</exception>
661         /// <since_tizen> 6 </since_tizen>
662         public static void SetDisplayModeCapability(MediaControlDisplayMode mode, MediaControlCapabilitySupport support)
663         {
664             ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
665             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
666
667             if (support == MediaControlCapabilitySupport.NotDecided)
668             {
669                 throw new ArgumentException($"NotDecided is not allowed in {mode} capability.");
670             }
671
672             Native.SetDisplayModeCapability(Handle, (uint)mode.ToNative(), support).
673                 ThrowIfError("Failed to set display mode capability.");
674         }
675
676         /// <summary>
677         /// Sets the supported list of <see cref="Rotation"/>.
678         /// </summary>
679         /// <remarks>
680         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
681         /// The default value of each <see cref="Rotation"/> is not supported.
682         /// </remarks>
683         /// <param name="capabilities">The supported list of <see cref="Rotation"/>.</param>
684         /// <exception cref="InvalidOperationException">
685         ///     The server is not running .<br/>
686         ///     -or-<br/>
687         ///     An internal error occurs.
688         /// </exception>
689         /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
690         /// <since_tizen> 6 </since_tizen>
691         public static void SetDisplayRotationCapabilities(IDictionary<Rotation, MediaControlCapabilitySupport> capabilities)
692         {
693             foreach (var pair in capabilities)
694             {
695                 SetDisplayRotationCapability(pair.Key, pair.Value);
696             }
697         }
698
699         /// <summary>
700         /// Sets the <paramref name="rotation"/> is supported or not.
701         /// </summary>
702         /// <remarks>
703         /// <see cref="MediaControlCapabilitySupport.NotDecided"/> is not allowed in display rotation capability.<br/>
704         /// The default value of each <see cref="Rotation"/> is not supported.
705         /// </remarks>
706         /// <param name="rotation">The <see cref="Rotation"/>.</param>
707         /// <param name="support">A value indicating whether the <paramref name="rotation"/> is supported or not..</param>
708         /// <exception cref="InvalidOperationException">
709         ///     The server is not running .<br/>
710         ///     -or-<br/>
711         ///     An internal error occurs.
712         /// </exception>
713         /// <exception cref="ArgumentException"><paramref name="rotation"/> or <paramref name="support"/> is invalid.</exception>
714         /// <since_tizen> 6 </since_tizen>
715         public static void SetDisplayRotationCapability(Rotation rotation, MediaControlCapabilitySupport support)
716         {
717             ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
718             ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
719
720             if (support == MediaControlCapabilitySupport.NotDecided)
721             {
722                 throw new ArgumentException($"NotDecided is not allowed in {rotation} capability.");
723             }
724
725             Native.SetDisplayRotationCapability(Handle, (uint)rotation.ToNative(), support).
726                 ThrowIfError("Failed to set display rotation capability.");
727         }
728         #endregion Capability
729
730
731         #region Command
732         /// <summary>
733         /// Requests commands to the client.
734         /// </summary>
735         /// <remarks>
736         /// The client can request the command to execute <see cref="Command"/>, <br/>
737         /// and then, the server receive the result of each request(command).
738         /// </remarks>
739         /// <param name="command">A <see cref="Command"/> class.</param>
740         /// <param name="clientId">The client Id to send command.</param>
741         /// <returns><see cref="Bundle"/> represents the extra data from client and it can be null.</returns>
742         /// <exception cref="ArgumentNullException">
743         /// <paramref name="command"/> or <paramref name="clientId"/> is null.
744         /// </exception>
745         /// <exception cref="InvalidOperationException">
746         ///     The server has already been stopped.<br/>
747         ///     -or-<br/>
748         ///     An internal error occurs.
749         /// </exception>
750         /// <since_tizen> 5 </since_tizen>
751         public static async Task<Bundle> RequestAsync(Command command, string clientId)
752         {
753             if (command == null)
754             {
755                 throw new ArgumentNullException(nameof(command));
756             }
757             if (clientId == null)
758             {
759                 throw new ArgumentNullException(nameof(clientId));
760             }
761
762             command.SetRequestInformation(clientId);
763
764             var tcs = new TaskCompletionSource<MediaControllerError>();
765             string reqeustId = null;
766             Bundle bundle = null;
767
768             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
769             {
770                 if (e.RequestId == reqeustId)
771                 {
772                     bundle = e.Bundle;
773                     tcs.TrySetResult(e.Result);
774                 }
775             };
776
777             try
778             {
779                 CommandCompleted += eventHandler;
780
781                 reqeustId = command.Request(Handle);
782
783                 (await tcs.Task).ThrowIfError("Failed to request event.");
784
785                 return bundle;
786             }
787             finally
788             {
789                 CommandCompleted -= eventHandler;
790             }
791         }
792
793         /// <summary>
794         /// Sends the result of each command.
795         /// </summary>
796         /// <param name="command">The command that return to client.</param>
797         /// <param name="result">The result of <paramref name="command"/>.</param>
798         /// <param name="bundle">The extra data.</param>
799         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
800         /// <exception cref="InvalidOperationException">
801         ///     The server is not running .<br/>
802         ///     -or-<br/>
803         ///     An internal error occurs.
804         /// </exception>
805         /// <since_tizen> 5 </since_tizen>
806         public static void Response(Command command, int result, Bundle bundle)
807         {
808             if (command == null)
809             {
810                 throw new ArgumentNullException(nameof(command));
811             }
812
813             command.Response(Handle, result, bundle);
814         }
815
816         /// <summary>
817         /// Sends the result of each command.
818         /// </summary>
819         /// <param name="command">The command that return to client.</param>
820         /// <param name="result">The result of <paramref name="command"/>.</param>
821         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
822         /// <exception cref="InvalidOperationException">
823         ///     The server is not running .<br/>
824         ///     -or-<br/>
825         ///     An internal error occurs.
826         /// </exception>
827         /// <since_tizen> 5 </since_tizen>
828         public static void Response(Command command, int result)
829         {
830             if (command == null)
831             {
832                 throw new ArgumentNullException(nameof(command));
833             }
834
835             command.Response(Handle, result, null);
836         }
837         #endregion Command
838     }
839 }