[MediaController] Add capability method for subtitle, 360 mode (#1048)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Remoting / MediaController / MediaController.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.Linq;
19 using System.Collections.Generic;
20 using System.Diagnostics;
21 using System.Threading.Tasks;
22 using Tizen.Applications;
23 using Native = Interop.MediaControllerClient;
24 using NativePlaylist = Interop.MediaControllerPlaylist;
25
26 namespace Tizen.Multimedia.Remoting
27 {
28     /// <summary>
29     /// Provides a means to send commands to and handle events from media control server.
30     /// </summary>
31     /// <since_tizen> 4 </since_tizen>
32     public partial class MediaController
33     {
34         internal MediaController(MediaControllerManager manager, string serverAppId)
35         {
36             Debug.Assert(manager != null);
37             Debug.Assert(serverAppId != null);
38
39             Manager = manager;
40             ServerAppId = serverAppId;
41         }
42
43         private MediaControllerManager Manager { get; }
44
45         /// <summary>
46         /// Gets the application id of the server.
47         /// </summary>
48         /// <value>The server application id.</value>
49         /// <since_tizen> 4 </since_tizen>
50         public string ServerAppId { get; }
51
52         /// <summary>
53         /// Gets a value indicating whether the sever has been stopped.
54         /// </summary>
55         /// <value>true if the server has been stopped; otherwise, false.</value>
56         /// <since_tizen> 4 </since_tizen>
57         public bool IsStopped
58         {
59             get;
60             private set;
61         }
62
63         private void ThrowIfStopped()
64         {
65             if (IsStopped)
66             {
67                 throw new InvalidOperationException("The server has already been stopped.");
68             }
69         }
70
71
72         #region Get information
73         /// <summary>
74         /// Returns the playback state set by the server.
75         /// </summary>
76         /// <returns>The playback state.</returns>
77         /// <exception cref="InvalidOperationException">
78         ///     The server has already been stopped.<br/>
79         ///     -or-<br/>
80         ///     An internal error occurs.
81         /// </exception>
82         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
83         /// <seealso cref="MediaControlServer.SetPlaybackState(MediaControlPlaybackState, long)"/>
84         /// <since_tizen> 4 </since_tizen>
85         public MediaControlPlaybackState GetPlaybackState()
86         {
87             ThrowIfStopped();
88
89             IntPtr playbackHandle = IntPtr.Zero;
90
91             try
92             {
93                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
94
95                 Native.GetPlaybackState(playbackHandle, out var playbackCode).ThrowIfError("Failed to get state.");
96
97                 return playbackCode.ToPublic();
98             }
99             finally
100             {
101                 if (playbackHandle != IntPtr.Zero)
102                 {
103                     Native.DestroyPlayback(playbackHandle);
104                 }
105             }
106         }
107
108         /// <summary>
109         /// Returns the playback position set by the server.
110         /// </summary>
111         /// <returns>The playback position in milliseconds.</returns>
112         /// <exception cref="InvalidOperationException">
113         ///     The server has already been stopped.<br/>
114         ///     -or-<br/>
115         ///     An internal error occurs.
116         /// </exception>
117         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
118         /// <seealso cref="MediaControlServer.SetPlaybackState(MediaControlPlaybackState, long)"/>
119         /// <since_tizen> 4 </since_tizen>
120         public long GetPlaybackPosition()
121         {
122             ThrowIfStopped();
123
124             IntPtr playbackHandle = IntPtr.Zero;
125
126             try
127             {
128                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
129
130                 Native.GetPlaybackPosition(playbackHandle, out var position).ThrowIfError("Failed to get position.");
131
132                 return (long)position;
133             }
134             finally
135             {
136                 if (playbackHandle != IntPtr.Zero)
137                 {
138                     Native.DestroyPlayback(playbackHandle);
139                 }
140             }
141         }
142
143         /// <summary>
144         /// Returns the metadata set by the server.
145         /// </summary>
146         /// <returns>The metadata.</returns>
147         /// <exception cref="InvalidOperationException">
148         ///     The server has already been stopped.<br/>
149         ///     -or-<br/>
150         ///     An internal error occurs.
151         /// </exception>
152         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
153         /// <seealso cref="MediaControlServer.SetMetadata(MediaControlMetadata)"/>
154         /// <since_tizen> 4 </since_tizen>
155         public MediaControlMetadata GetMetadata()
156         {
157             ThrowIfStopped();
158
159             IntPtr metadataHandle = IntPtr.Zero;
160
161             try
162             {
163                 NativePlaylist.GetServerMetadata(Manager.Handle, ServerAppId, out metadataHandle).
164                     ThrowIfError("Failed to get metadata.");
165
166                 return new MediaControlMetadata(metadataHandle);
167             }
168             finally
169             {
170                 if (metadataHandle != IntPtr.Zero)
171                 {
172                     NativePlaylist.DestroyMetadata(metadataHandle);
173                 }
174             }
175         }
176
177         /// <summary>
178         /// Returns the all playlists.
179         /// </summary>
180         /// <returns>The set of <see cref="MediaControlPlaylist"/>.</returns>
181         /// <exception cref="InvalidOperationException">
182         ///     The server has already been stopped.<br/>
183         ///     -or-<br/>
184         ///     An internal error occurs.
185         /// </exception>
186         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
187         /// <since_tizen> 5 </since_tizen>
188         public IEnumerable<MediaControlPlaylist> GetPlaylists()
189         {
190             ThrowIfStopped();
191
192             var playlists = new List<MediaControlPlaylist>();
193
194             Exception caught = null;
195
196             NativePlaylist.PlaylistCallback playlistCallback = (handle, _) =>
197             {
198                 try
199                 {
200                     playlists.Add(new MediaControlPlaylist(handle));
201                     return true;
202                 }
203                 catch (Exception e)
204                 {
205                     caught = e;
206                     return false;
207                 }
208             };
209
210             NativePlaylist.ForeachPlaylist(ServerAppId, playlistCallback, IntPtr.Zero).
211                 ThrowIfError("Failed to get playlist.");
212
213             if (caught != null)
214             {
215                 throw caught;
216             }
217
218             return playlists.AsReadOnly();
219         }
220
221         /// <summary>
222         /// Returns the playlist name of current playing media.
223         /// </summary>
224         /// <returns>The playlist name.</returns>
225         /// <exception cref="InvalidOperationException">
226         ///     The server has already been stopped.<br/>
227         ///     -or-<br/>
228         ///     An internal error occurs.
229         /// </exception>
230         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
231         /// <since_tizen> 5 </since_tizen>
232         public MediaControlPlaylist GetPlaylistOfCurrentPlayingMedia()
233         {
234             ThrowIfStopped();
235
236             IntPtr playbackHandle = IntPtr.Zero;
237
238             // Get the playlist name of current playing media.
239             try
240             {
241                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
242
243                 var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle);
244
245                 return GetPlaylists().FirstOrDefault(playlist => playlist.Name == name);
246             }
247             finally
248             {
249                 if (playbackHandle != IntPtr.Zero)
250                 {
251                     Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle.");
252                 }
253             }
254         }
255
256         /// <summary>
257         /// Returns the index of current playing media.
258         /// </summary>
259         /// <returns>The index of current playing media.</returns>
260         /// <exception cref="InvalidOperationException">
261         ///     The server has already been stopped.<br/>
262         ///     -or-<br/>
263         ///     An internal error occurs.
264         /// </exception>
265         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
266         /// <since_tizen> 5 </since_tizen>
267         public string GetIndexOfCurrentPlayingMedia()
268         {
269             ThrowIfStopped();
270
271             IntPtr playbackHandle = IntPtr.Zero;
272
273             try
274             {
275                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
276
277                 var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle);
278                 return index;
279             }
280             finally
281             {
282                 if (playbackHandle != IntPtr.Zero)
283                 {
284                     Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle.");
285                 }
286             }
287         }
288
289         /// <summary>
290         /// Returns whether the shuffle mode is enabled.
291         /// </summary>
292         /// <returns>A value indicating whether the shuffle mode is enabled.</returns>
293         /// <exception cref="InvalidOperationException">
294         ///     The server has already been stopped.<br/>
295         ///     -or-<br/>
296         ///     An internal error occurs.
297         /// </exception>
298         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
299         /// <seealso cref="MediaControlServer.SetShuffleModeEnabled(bool)"/>
300         /// <since_tizen> 4 </since_tizen>
301         public bool IsShuffleModeEnabled()
302         {
303             ThrowIfStopped();
304
305             Native.GetServerShuffleMode(Manager.Handle, ServerAppId, out var shuffleMode).
306                 ThrowIfError("Failed to get shuffle mode state.");
307
308             return shuffleMode == MediaControllerNativeShuffleMode.On;
309         }
310
311         /// <summary>
312         /// Returns the repeat mode.
313         /// </summary>
314         /// <returns>A <see cref="MediaControlRepeatMode"/> set by the server.</returns>
315         /// <exception cref="InvalidOperationException">
316         ///     The server has already been stopped.<br/>
317         ///     -or-<br/>
318         ///     An internal error occurs.
319         /// </exception>
320         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
321         /// <seealso cref="MediaControlServer.SetRepeatMode(MediaControlRepeatMode)"/>
322         /// <since_tizen> 4 </since_tizen>
323         public MediaControlRepeatMode GetRepeatMode()
324         {
325             ThrowIfStopped();
326
327             Native.GetServerRepeatMode(Manager.Handle, ServerAppId, out var repeatMode).
328                 ThrowIfError("Failed to get repeat mode state.");
329
330             return repeatMode.ToPublic();
331         }
332
333         /// <summary>
334         /// Gets the content type of current playing media.
335         /// </summary>
336         /// <returns>The <see cref="MediaControlContentType"/>.</returns>
337         /// <exception cref="InvalidOperationException">
338         ///     The server has already been stopped.<br/>
339         ///     -or-<br/>
340         ///     An internal error occurs.
341         /// </exception>
342         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
343         /// <since_tizen> 5 </since_tizen>
344         public MediaControlContentType GetContentTypeOfCurrentPlayingMedia()
345         {
346             ThrowIfStopped();
347
348             IntPtr playbackHandle = IntPtr.Zero;
349
350             try
351             {
352                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
353
354                 Native.GetPlaybackContentType(playbackHandle, out MediaControlContentType type).
355                     ThrowIfError("Failed to get playback content type");
356
357                 return type;
358             }
359             finally
360             {
361                 if (playbackHandle != IntPtr.Zero)
362                 {
363                     Native.DestroyPlayback(playbackHandle);
364                 }
365             }
366         }
367
368         /// <summary>
369         /// Gets the icon path.
370         /// </summary>
371         /// <returns>The icon path.</returns>
372         /// <exception cref="InvalidOperationException">
373         ///     The server has already been stopped.<br/>
374         ///     -or-<br/>
375         ///     An internal error occurs.
376         /// </exception>
377         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
378         /// <since_tizen> 5 </since_tizen>
379         public string GetIconPath()
380         {
381             ThrowIfStopped();
382
383             Native.GetServerIcon(Manager.Handle, ServerAppId, out string uri).
384                 ThrowIfError("Failed to get icon path.");
385
386             return uri;
387         }
388
389         /// <summary>
390         /// Gets the age rating of current playing media.
391         /// </summary>
392         /// <returns>The Age rating of current playing media. The range is 0 to 19, inclusive.</returns>
393         /// <exception cref="InvalidOperationException">
394         ///     The server has already been stopped.<br/>
395         ///     -or-<br/>
396         ///     An internal error occurs.
397         /// </exception>
398         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
399         /// <since_tizen> 5 </since_tizen>
400         public int GetAgeRatingOfCurrentPlayingMedia()
401         {
402             ThrowIfStopped();
403
404             IntPtr playbackHandle = IntPtr.Zero;
405
406             try
407             {
408                 Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
409
410                 Native.GetAgeRating(playbackHandle, out int ageRating).ThrowIfError("Failed to get age rating.");
411
412                 return ageRating;
413             }
414             finally
415             {
416                 if (playbackHandle != IntPtr.Zero)
417                 {
418                     Native.DestroyPlayback(playbackHandle);
419                 }
420             }
421         }
422
423         /// <summary>
424         /// Gets whether the subtitle mode is enabled or not.
425         /// </summary>
426         /// <returns>A value indicating whether the subtitle mode is enabled or not.</returns>
427         /// <value>true if the subtitle mode is enabled; otherwise, false.</value>
428         /// <exception cref="InvalidOperationException">
429         ///     The server has already been stopped.<br/>
430         ///     -or-<br/>
431         ///     An internal error occurs.
432         /// </exception>
433         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
434         /// <since_tizen> 6 </since_tizen>
435         public bool IsSubtitleModeEnabled()
436         {
437             ThrowIfStopped();
438
439             Native.IsSubtitleEnabled(Manager.Handle, ServerAppId, out var isEnabled).
440                 ThrowIfError("Failed to get subtitle mode state.");
441
442             return isEnabled;
443         }
444
445         /// <summary>
446         /// Gets whether the 360 mode is enabled or not.
447         /// </summary>
448         /// <returns>A value indicating whether the 360 mode is enabled or not.</returns>
449         /// <value>true if the 360 mode is enabled; otherwise, false.</value>
450         /// <exception cref="InvalidOperationException">
451         ///     The server has already been stopped.<br/>
452         ///     -or-<br/>
453         ///     An internal error occurs.
454         /// </exception>
455         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
456         /// <since_tizen> 6 </since_tizen>
457         public bool IsMode360Enabled()
458         {
459             ThrowIfStopped();
460
461             Native.IsMode360Enabled(Manager.Handle, ServerAppId, out var isEnabled).
462                 ThrowIfError("Failed to get 360 mode state.");
463
464             return isEnabled;
465         }
466
467         /// <summary>
468         /// Gets the current display mode.
469         /// </summary>
470         /// <returns>The <see cref="MediaControlDisplayMode"/>.</returns>
471         /// <exception cref="InvalidOperationException">
472         ///     The server has already been stopped.<br/>
473         ///     -or-<br/>
474         ///     An internal error occurs.
475         /// </exception>
476         /// <exception cref="ObjectDisposedException">
477         /// The <see cref="MediaControllerManager"/> has already been disposed.
478         /// </exception>
479         /// <since_tizen> 6 </since_tizen>
480         public MediaControlDisplayMode GetDisplayMode()
481         {
482             ThrowIfStopped();
483
484             Native.GetDisplayMode(Manager.Handle, ServerAppId, out var mode).
485                 ThrowIfError("Failed to get display mode state.");
486
487             return mode.ToPublic();
488         }
489
490         /// <summary>
491         /// Gets the current display rotation.
492         /// </summary>
493         /// <returns>The <see cref="Rotation"/>.</returns>
494         /// <exception cref="InvalidOperationException">
495         ///     The server has already been stopped.<br/>
496         ///     -or-<br/>
497         ///     An internal error occurs.
498         /// </exception>
499         /// <exception cref="ObjectDisposedException">
500         /// The <see cref="MediaControllerManager"/> has already been disposed.
501         /// </exception>
502         /// <since_tizen> 6 </since_tizen>
503         public Rotation GetDisplayRotation()
504         {
505             ThrowIfStopped();
506
507             Native.GetDisplayRotation(Manager.Handle, ServerAppId, out var rotation).
508                 ThrowIfError("Failed to get display rotation state.");
509
510             return rotation.ToPublic();
511         }
512         #endregion Get information
513
514
515         #region Capability
516         /// <summary>
517         /// Gets the value whether <see cref="MediaControlPlaybackCommand"/> is supported or not.
518         /// </summary>
519         /// <returns>
520         /// the set of <see cref="MediaControlPlaybackCommand"/> and <see cref="MediaControlCapabilitySupport"/>.
521         /// </returns>
522         /// <exception cref="InvalidOperationException">
523         ///     The server has already been stopped.<br/>
524         ///     -or-<br/>
525         ///     An internal error occurs.
526         /// </exception>
527         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
528         /// <since_tizen> 5 </since_tizen>
529         public Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport> GetPlaybackCapabilities()
530         {
531             ThrowIfStopped();
532
533             IntPtr playbackCapaHandle = IntPtr.Zero;
534
535             var playbackCapabilities = new Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport>();
536
537             try
538             {
539                 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
540                     ThrowIfError("Failed to get playback capability handle.");
541
542                 foreach (MediaControllerNativePlaybackAction action in Enum.GetValues(typeof(MediaControllerNativePlaybackAction)))
543                 {
544                     Native.GetPlaybackCapability(playbackCapaHandle, action, out MediaControlCapabilitySupport support);
545                     playbackCapabilities.Add(action.ToPublic(), support);
546                 }
547
548                 return playbackCapabilities;
549             }
550             finally
551             {
552                 if (playbackCapaHandle != IntPtr.Zero)
553                 {
554                     Native.DestroyCapability(playbackCapaHandle);
555                 }
556             }
557         }
558
559         /// <summary>
560         /// Gets the value whether <paramref name="action"/> is supported or not.
561         /// </summary>
562         /// <param name="action">A playback command.</param>
563         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
564         /// <exception cref="ArgumentException"><paramref name="action"/> is not valid.</exception>
565         /// <exception cref="InvalidOperationException">
566         ///     The server has already been stopped.<br/>
567         ///     -or-<br/>
568         ///     An internal error occurs.
569         /// </exception>
570         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
571         /// <since_tizen> 5 </since_tizen>
572         public MediaControlCapabilitySupport GetPlaybackCapability(MediaControlPlaybackCommand action)
573         {
574             ThrowIfStopped();
575
576             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
577
578             IntPtr playbackCapaHandle = IntPtr.Zero;
579
580             try
581             {
582                 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
583                     ThrowIfError("Failed to get playback capability handle.");
584
585                 Native.GetPlaybackCapability(playbackCapaHandle, action.ToNative(), out MediaControlCapabilitySupport support);
586
587                 return support;
588             }
589             finally
590             {
591                 if (playbackCapaHandle != IntPtr.Zero)
592                 {
593                     Native.DestroyCapability(playbackCapaHandle);
594                 }
595             }
596         }
597
598         /// <summary>
599         /// Gets the value whether the shuffle mode is supported or not.
600         /// </summary>
601         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
602         /// <exception cref="InvalidOperationException">
603         ///     The server has already been stopped.<br/>
604         ///     -or-<br/>
605         ///     An internal error occurs.
606         /// </exception>
607         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
608         /// <since_tizen> 5 </since_tizen>
609         public MediaControlCapabilitySupport GetShuffleModeCapability()
610         {
611             ThrowIfStopped();
612
613             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Shuffle, out MediaControlCapabilitySupport support).
614                 ThrowIfError("Failed to get shuffle mode capability");
615
616             return support;
617         }
618
619         /// <summary>
620         /// Gets the value whether the repeat mode is supported or not.
621         /// </summary>
622         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
623         /// <exception cref="InvalidOperationException">
624         ///     The server has already been stopped.<br/>
625         ///     -or-<br/>
626         ///     An internal error occurs.
627         /// </exception>
628         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
629         /// <since_tizen> 5 </since_tizen>
630         public MediaControlCapabilitySupport GetRepeatModeCapability()
631         {
632             ThrowIfStopped();
633
634             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Repeat, out MediaControlCapabilitySupport support).
635                 ThrowIfError("Failed to get repeat mode capability");
636
637             return support;
638         }
639
640         /// <summary>
641         /// Gets the value whether the 360 mode is supported or not.
642         /// </summary>
643         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
644         /// <exception cref="InvalidOperationException">
645         ///     The server has already been stopped.<br/>
646         ///     -or-<br/>
647         ///     An internal error occurs.
648         /// </exception>
649         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
650         /// <since_tizen> 6 </since_tizen>
651         public MediaControlCapabilitySupport GetMode360Capability()
652         {
653             ThrowIfStopped();
654
655             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Mode360, out MediaControlCapabilitySupport support).
656                 ThrowIfError("Failed to get 360 mode capability");
657
658             return support;
659         }
660
661         /// <summary>
662         /// Gets the value whether the subtitle mode is supported or not.
663         /// </summary>
664         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
665         /// <exception cref="InvalidOperationException">
666         ///     The server has already been stopped.<br/>
667         ///     -or-<br/>
668         ///     An internal error occurs.
669         /// </exception>
670         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
671         /// <since_tizen> 6 </since_tizen>
672         public MediaControlCapabilitySupport GetSubtitleModeCapability()
673         {
674             ThrowIfStopped();
675
676             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Subtitle, out MediaControlCapabilitySupport support).
677                 ThrowIfError("Failed to get subtitle mode capability");
678
679             return support;
680         }
681
682         /// <summary>
683         /// Gets the value whether the repeat mode is supported or not.
684         /// </summary>
685         /// <returns>
686         /// If there's no supported display mode by server, it will return null.
687         /// otherwise, it will return the supported list of <see cref="MediaControlDisplayMode"/>.
688         /// </returns>
689         /// <exception cref="InvalidOperationException">
690         ///     The server has already been stopped.<br/>
691         ///     -or-<br/>
692         ///     An internal error occurs.
693         /// </exception>
694         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
695         /// <since_tizen> 6 </since_tizen>
696         public IEnumerable<MediaControlDisplayMode> GetDisplayModeCapability()
697         {
698             ThrowIfStopped();
699
700             Native.GetDisplayModeCapability(Manager.Handle, ServerAppId, out uint support).
701                 ThrowIfError("Failed to get display mode capability");
702
703             return support != 0 ? ((MediaControlNativeDisplayMode)support).ToPublicList() : null;
704         }
705
706         /// <summary>
707         /// Gets the value whether the display mode is supported or not.
708         /// </summary>
709         /// <returns>
710         /// If there's no supported display rotation by server, it will return null.
711         /// otherwise, it will return the supported list of <see cref="Rotation"/>.
712         /// </returns>
713         /// <exception cref="InvalidOperationException">
714         ///     The server has already been stopped.<br/>
715         ///     -or-<br/>
716         ///     An internal error occurs.
717         /// </exception>
718         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
719         /// <since_tizen> 6 </since_tizen>
720         public IEnumerable<Rotation> GetDisplayRotationapability()
721         {
722             ThrowIfStopped();
723
724             Native.GetDisplayRotationCapability(Manager.Handle, ServerAppId, out uint support).
725                 ThrowIfError("Failed to get display mode capability");
726
727             return support != 0 ? ((MediaControlNativeDisplayRotation)support).ToPublicList() : null;
728         }
729         #endregion Capability
730
731
732         #region Command
733         /// <summary>
734         /// Requests command to the server.
735         /// </summary>
736         /// <remarks>
737         /// The client can request the server to execute <see cref="PlaybackCommand"/> or <see cref="ShuffleModeCommand"/> or
738         /// <see cref="RepeatModeCommand"/> or <see cref="CustomCommand"/>, <br/>
739         /// and then, the client receive the result of each request(command).
740         /// </remarks>
741         /// <param name="command">A <see cref="Command"/> class.</param>
742         /// <returns><see cref="Bundle"/> represents the extra data from server and it can be null.</returns>
743         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
744         /// <exception cref="InvalidOperationException">
745         ///     The server has already been stopped.<br/>
746         ///     -or-<br/>
747         ///     An internal error occurs.
748         /// </exception>
749         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
750         /// <since_tizen> 5 </since_tizen>
751         public async Task<Bundle> RequestAsync(Command command)
752         {
753             if (command == null)
754             {
755                 throw new ArgumentNullException(nameof(command));
756             }
757
758             ThrowIfStopped();
759
760             command.SetRequestInformation(ServerAppId);
761
762             var tcs = new TaskCompletionSource<MediaControllerError>();
763             string reqeustId = null;
764             Bundle bundle = null;
765
766             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
767             {
768                 if (e.RequestId == reqeustId)
769                 {
770                     bundle = e.Bundle;
771                     tcs.TrySetResult(e.Result);
772                 }
773             };
774
775             try
776             {
777                 CommandCompleted += eventHandler;
778
779                 reqeustId = command.Request(Manager.Handle);
780
781                 (await tcs.Task).ThrowIfError("Failed to request command");
782
783                 return bundle;
784             }
785             finally
786             {
787                 CommandCompleted -= eventHandler;
788             }
789         }
790
791         /// <summary>
792         /// Sends the result of each command.
793         /// </summary>
794         /// <param name="command">The command that return to client.</param>
795         /// <param name="result">The result of <paramref name="command"/>.</param>
796         /// <param name="bundle">The extra data.</param>
797         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
798         /// <exception cref="InvalidOperationException">
799         ///     The server is not running .<br/>
800         ///     -or-<br/>
801         ///     An internal error occurs.
802         /// </exception>
803         /// <since_tizen> 5 </since_tizen>
804         public void Response(Command command, int result, Bundle bundle)
805         {
806             if (command == null)
807             {
808                 throw new ArgumentNullException(nameof(command));
809             }
810
811             command.Response(Manager.Handle, result, bundle);
812         }
813
814         /// <summary>
815         /// Sends the result of each command.
816         /// </summary>
817         /// <param name="command">The command that return to client.</param>
818         /// <param name="result">The result of <paramref name="command"/>.</param>
819         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
820         /// <exception cref="InvalidOperationException">
821         ///     The server is not running .<br/>
822         ///     -or-<br/>
823         ///     An internal error occurs.
824         /// </exception>
825         /// <since_tizen> 5 </since_tizen>
826         public void Response(Command command, int result)
827         {
828             if (command == null)
829             {
830                 throw new ArgumentNullException(nameof(command));
831             }
832
833             command.Response(Manager.Handle, result, null);
834         }
835
836         /// <summary>
837         /// Sends playback command to the server.
838         /// </summary>
839         /// <param name="command">A playback command.</param>
840         /// <exception cref="InvalidOperationException">
841         ///     The server has already been stopped.<br/>
842         ///     -or-<br/>
843         ///     An internal error occurs.
844         /// </exception>
845         /// <exception cref="ArgumentException"><paramref name="command"/> is not valid.</exception>
846         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
847         /// <seealso cref="MediaControlServer.PlaybackCommandReceived"/>
848         /// <since_tizen> 4 </since_tizen>
849         [Obsolete("Please do not use! This will be deprecated. Please use Request instead.")]
850         public void SendPlaybackCommand(MediaControlPlaybackCommand command)
851         {
852             ThrowIfStopped();
853
854             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), command, nameof(command));
855
856             Native.SendPlaybackActionCommandWithoutReqId(Manager.Handle, ServerAppId, command.ToNative()).
857                 ThrowIfError("Failed to send command.");
858         }
859         #endregion Command
860     }
861 }