[MediaController] Add new capability APIs (#5472)
[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 playback position is supported or not.
684         /// </summary>
685         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
686         /// <exception cref="InvalidOperationException">
687         ///     The server has already been stopped.<br/>
688         ///     -or-<br/>
689         ///     An internal error occurs.
690         /// </exception>
691         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
692         /// <since_tizen> 11 </since_tizen>
693         public MediaControlCapabilitySupport GetPlaybackPositionCapability()
694         {
695             ThrowIfStopped();
696
697             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.PlaybackPosition, out MediaControlCapabilitySupport support).
698                 ThrowIfError("Failed to get playback position capability");
699
700             return support;
701         }
702
703         /// <summary>
704         /// Gets the value whether the playlist is supported or not.
705         /// </summary>
706         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
707         /// <exception cref="InvalidOperationException">
708         ///     The server has already been stopped.<br/>
709         ///     -or-<br/>
710         ///     An internal error occurs.
711         /// </exception>
712         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
713         /// <since_tizen> 11 </since_tizen>
714         public MediaControlCapabilitySupport GetPlaylistCapability()
715         {
716             ThrowIfStopped();
717
718             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Playlist, out MediaControlCapabilitySupport support).
719                 ThrowIfError("Failed to get playlist capability");
720
721             return support;
722         }
723
724         /// <summary>
725         /// Gets the value whether the custom command is supported or not.
726         /// </summary>
727         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
728         /// <exception cref="InvalidOperationException">
729         ///     The server has already been stopped.<br/>
730         ///     -or-<br/>
731         ///     An internal error occurs.
732         /// </exception>
733         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
734         /// <since_tizen> 11 </since_tizen>
735         public MediaControlCapabilitySupport GetCustomCommandCapability()
736         {
737             ThrowIfStopped();
738
739             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.CustomCommand, out MediaControlCapabilitySupport support).
740                 ThrowIfError("Failed to get custom command capability");
741
742             return support;
743         }
744
745         /// <summary>
746         /// Gets the value whether the search is supported or not.
747         /// </summary>
748         /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
749         /// <exception cref="InvalidOperationException">
750         ///     The server has already been stopped.<br/>
751         ///     -or-<br/>
752         ///     An internal error occurs.
753         /// </exception>
754         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
755         /// <since_tizen> 11 </since_tizen>
756         public MediaControlCapabilitySupport GetSearchCapability()
757         {
758             ThrowIfStopped();
759
760             Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Search, out MediaControlCapabilitySupport support).
761                 ThrowIfError("Failed to get search capability");
762
763             return support;
764         }
765
766         /// <summary>
767         /// Gets the value whether the repeat mode is supported or not.
768         /// </summary>
769         /// <returns>
770         /// If there's no supported display mode by server, it will return null.
771         /// otherwise, it will return the supported list of <see cref="MediaControlDisplayMode"/>.
772         /// </returns>
773         /// <exception cref="InvalidOperationException">
774         ///     The server has already been stopped.<br/>
775         ///     -or-<br/>
776         ///     An internal error occurs.
777         /// </exception>
778         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
779         /// <since_tizen> 6 </since_tizen>
780         public IEnumerable<MediaControlDisplayMode> GetDisplayModeCapability()
781         {
782             ThrowIfStopped();
783
784             Native.GetDisplayModeCapability(Manager.Handle, ServerAppId, out uint support).
785                 ThrowIfError("Failed to get display mode capability");
786
787             return support != 0 ? ((MediaControlNativeDisplayMode)support).ToPublicList() : null;
788         }
789
790         /// <summary>
791         /// Gets the value whether the display mode is supported or not.
792         /// </summary>
793         /// <returns>
794         /// If there's no supported display rotation by server, it will return null.
795         /// otherwise, it will return the supported list of <see cref="Rotation"/>.
796         /// </returns>
797         /// <exception cref="InvalidOperationException">
798         ///     The server has already been stopped.<br/>
799         ///     -or-<br/>
800         ///     An internal error occurs.
801         /// </exception>
802         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
803         /// <since_tizen> 6 </since_tizen>
804         public IEnumerable<Rotation> GetDisplayRotationCapability()
805         {
806             ThrowIfStopped();
807
808             Native.GetDisplayRotationCapability(Manager.Handle, ServerAppId, out uint support).
809                 ThrowIfError("Failed to get display mode capability");
810
811             return support != 0 ? ((MediaControlNativeDisplayRotation)support).ToPublicList() : null;
812         }
813         #endregion Capability
814
815
816         #region Command
817         /// <summary>
818         /// Requests a command to the server and client receives the result of each request(command).
819         /// </summary>
820         /// <param name="command">A <see cref="Command"/> class.</param>
821         /// <returns>
822         /// The type of return value is Tuple.<br/>
823         /// First item of Tuple represents the <see cref="Bundle"/> and it represents the extra data from client. It can be null.<br/>
824         /// Second item of Tuple represents the result of each request(command).
825         /// </returns>
826         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
827         /// <exception cref="InvalidOperationException">
828         ///     The server has already been stopped.<br/>
829         ///     -or-<br/>
830         ///     An internal error occurs.
831         /// </exception>
832         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
833         /// <seealso cref="PlaybackCommand"/>
834         /// <seealso cref="PlaybackPositionCommand"/>
835         /// <seealso cref="PlaylistCommand"/>
836         /// <seealso cref="ShuffleModeCommand"/>
837         /// <seealso cref="RepeatModeCommand"/>
838         /// <seealso cref="SubtitleModeCommand"/>
839         /// <seealso cref="Mode360Command"/>
840         /// <seealso cref="DisplayModeCommand"/>
841         /// <seealso cref="DisplayRotationCommand"/>
842         /// <seealso cref="CustomCommand"/>
843         /// <seealso cref="SearchCommand"/>
844         /// <since_tizen> 8 </since_tizen>
845         public async Task<(Bundle bundle, int result)> RequestCommandAsync(Command command)
846         {
847             if (command == null)
848             {
849                 throw new ArgumentNullException(nameof(command));
850             }
851
852             ThrowIfStopped();
853
854             command.SetRequestInformation(ServerAppId);
855
856             var tcs = new TaskCompletionSource<int>();
857             string reqeustId = null;
858             Bundle bundle = null;
859
860             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
861             {
862                 if (e.RequestId == reqeustId)
863                 {
864                     bundle = e.Bundle;
865                     tcs.TrySetResult(e.Result);
866                 }
867             };
868
869             try
870             {
871                 CommandCompleted += eventHandler;
872
873                 reqeustId = command.Request(Manager.Handle);
874
875                 var result = await tcs.Task;
876
877                 return (bundle, result);
878             }
879             finally
880             {
881                 CommandCompleted -= eventHandler;
882             }
883         }
884
885         /// <summary>
886         /// Requests command to the server.
887         /// </summary>
888         /// <param name="command">A <see cref="Command"/> class.</param>
889         /// <returns><see cref="Bundle"/> represents the extra data from server and it can be null.</returns>
890         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
891         /// <exception cref="InvalidOperationException">
892         ///     The server has already been stopped.<br/>
893         ///     -or-<br/>
894         ///     An internal error occurs.
895         /// </exception>
896         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
897         /// <seealso cref="PlaybackCommand"/>
898         /// <seealso cref="PlaybackPositionCommand"/>
899         /// <seealso cref="PlaylistCommand"/>
900         /// <seealso cref="ShuffleModeCommand"/>
901         /// <seealso cref="RepeatModeCommand"/>
902         /// <seealso cref="SubtitleModeCommand"/>
903         /// <seealso cref="Mode360Command"/>
904         /// <seealso cref="DisplayModeCommand"/>
905         /// <seealso cref="DisplayRotationCommand"/>
906         /// <seealso cref="CustomCommand"/>
907         /// <seealso cref="SearchCommand"/>
908         /// <since_tizen> 5 </since_tizen>
909         [Obsolete("Deprecated since API8; Will be removed in API10. Please use RequestCommandAsync(Command command) instead.")]
910         public async Task<Bundle> RequestAsync(Command command)
911         {
912             if (command == null)
913             {
914                 throw new ArgumentNullException(nameof(command));
915             }
916
917             ThrowIfStopped();
918
919             command.SetRequestInformation(ServerAppId);
920
921             var tcs = new TaskCompletionSource<int>();
922             string reqeustId = null;
923             Bundle bundle = null;
924
925             EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
926             {
927                 if (e.RequestId == reqeustId)
928                 {
929                     bundle = e.Bundle;
930                     tcs.TrySetResult(e.Result);
931                 }
932             };
933
934             try
935             {
936                 CommandCompleted += eventHandler;
937
938                 reqeustId = command.Request(Manager.Handle);
939
940                 ((MediaControllerError)await tcs.Task).ThrowIfError("Failed to request command");
941
942                 return bundle;
943             }
944             finally
945             {
946                 CommandCompleted -= eventHandler;
947             }
948         }
949
950         /// <summary>
951         /// Sends the result of each command.
952         /// </summary>
953         /// <param name="command">The command that return to client.</param>
954         /// <param name="result">The result of <paramref name="command"/>.</param>
955         /// <param name="bundle">The extra data.</param>
956         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
957         /// <exception cref="InvalidOperationException">
958         ///     The server is not running .<br/>
959         ///     -or-<br/>
960         ///     An internal error occurs.
961         /// </exception>
962         /// <since_tizen> 5 </since_tizen>
963         public void Response(Command command, int result, Bundle bundle)
964         {
965             if (command == null)
966             {
967                 throw new ArgumentNullException(nameof(command));
968             }
969
970             command.Response(Manager.Handle, result, bundle);
971         }
972
973         /// <summary>
974         /// Sends the result of each command.
975         /// </summary>
976         /// <param name="command">The command that return to client.</param>
977         /// <param name="result">The result of <paramref name="command"/>.</param>
978         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
979         /// <exception cref="InvalidOperationException">
980         ///     The server is not running .<br/>
981         ///     -or-<br/>
982         ///     An internal error occurs.
983         /// </exception>
984         /// <since_tizen> 5 </since_tizen>
985         public void Response(Command command, int result)
986         {
987             Response(command, result, null);
988         }
989
990         /// <summary>
991         /// Sends the result of each command.
992         /// </summary>
993         /// <param name="command">The command that return to client.</param>
994         /// <param name="result">The <see cref="MediaControlResult"/> of <paramref name="command"/>.</param>
995         /// <param name="bundle">The extra data.</param>
996         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
997         /// <exception cref="InvalidOperationException">
998         ///     The server is not running .<br/>
999         ///     -or-<br/>
1000         ///     An internal error occurs.
1001         /// </exception>
1002         /// <since_tizen> 8 </since_tizen>
1003         public void Response(Command command, MediaControlResult result, Bundle bundle)
1004         {
1005             Response(command, (int)result, bundle);
1006         }
1007
1008         /// <summary>
1009         /// Sends the result of each command.
1010         /// </summary>
1011         /// <param name="command">The command that return to client.</param>
1012         /// <param name="result">The <see cref="MediaControlResult"/> of <paramref name="command"/>.</param>
1013         /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
1014         /// <exception cref="InvalidOperationException">
1015         ///     The server is not running .<br/>
1016         ///     -or-<br/>
1017         ///     An internal error occurs.
1018         /// </exception>
1019         /// <since_tizen> 8 </since_tizen>
1020         public void Response(Command command, MediaControlResult result)
1021         {
1022             Response(command, (int)result, null);
1023         }
1024
1025         /// <summary>
1026         /// Sends playback command to the server.
1027         /// </summary>
1028         /// <param name="command">A playback command.</param>
1029         /// <exception cref="InvalidOperationException">
1030         ///     The server has already been stopped.<br/>
1031         ///     -or-<br/>
1032         ///     An internal error occurs.
1033         /// </exception>
1034         /// <exception cref="ArgumentException"><paramref name="command"/> is not valid.</exception>
1035         /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed.</exception>
1036         /// <seealso cref="MediaControlServer.PlaybackCommandReceived"/>
1037         /// <since_tizen> 4 </since_tizen>
1038         [Obsolete("Please do not use! This will be deprecated. Please use Request instead.")]
1039         public void SendPlaybackCommand(MediaControlPlaybackCommand command)
1040         {
1041             ThrowIfStopped();
1042
1043             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), command, nameof(command));
1044
1045             Native.SendPlaybackActionCommandWithoutReqId(Manager.Handle, ServerAppId, command.ToNative()).
1046                 ThrowIfError("Failed to send command.");
1047         }
1048         #endregion Command
1049     }
1050 }