2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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;
26 namespace Tizen.Multimedia.Remoting
29 /// Provides a means to send commands to and handle events from media control server.
31 /// <since_tizen> 4 </since_tizen>
32 public partial class MediaController
34 internal MediaController(MediaControllerManager manager, string serverAppId)
36 Debug.Assert(manager != null);
37 Debug.Assert(serverAppId != null);
40 ServerAppId = serverAppId;
43 private MediaControllerManager Manager { get; }
46 /// Gets the application id of the server.
48 /// <value>The server application id.</value>
49 /// <since_tizen> 4 </since_tizen>
50 public string ServerAppId { get; }
53 /// Gets a value indicating whether the sever has been stopped.
55 /// <value>true if the server has been stopped; otherwise, false.</value>
56 /// <since_tizen> 4 </since_tizen>
63 private void ThrowIfStopped()
67 throw new InvalidOperationException("The server has already been stopped.");
72 /// Returns the playback state set by the server.
74 /// <returns>The playback state.</returns>
75 /// <exception cref="InvalidOperationException">
76 /// The server has already been stopped.<br/>
78 /// An internal error occurs.
80 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
81 /// <seealso cref="MediaControlServer.SetPlaybackState(MediaControlPlaybackState, long)"/>
82 /// <since_tizen> 4 </since_tizen>
83 public MediaControlPlaybackState GetPlaybackState()
87 IntPtr playbackHandle = IntPtr.Zero;
91 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
93 Native.GetPlaybackState(playbackHandle, out var playbackCode).ThrowIfError("Failed to get state.");
95 return playbackCode.ToPublic();
99 if (playbackHandle != IntPtr.Zero)
101 Native.DestroyPlayback(playbackHandle);
107 /// Returns the playback position set by the server.
109 /// <returns>The playback position in milliseconds.</returns>
110 /// <exception cref="InvalidOperationException">
111 /// The server has already been stopped.<br/>
113 /// An internal error occurs.
115 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
116 /// <seealso cref="MediaControlServer.SetPlaybackState(MediaControlPlaybackState, long)"/>
117 /// <since_tizen> 4 </since_tizen>
118 public long GetPlaybackPosition()
122 IntPtr playbackHandle = IntPtr.Zero;
126 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
128 Native.GetPlaybackPosition(playbackHandle, out var position).ThrowIfError("Failed to get position.");
130 return (long)position;
134 if (playbackHandle != IntPtr.Zero)
136 Native.DestroyPlayback(playbackHandle);
142 /// Returns the metadata set by the server.
144 /// <returns>The metadata.</returns>
145 /// <exception cref="InvalidOperationException">
146 /// The server has already been stopped.<br/>
148 /// An internal error occurs.
150 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
151 /// <seealso cref="MediaControlServer.SetMetadata(MediaControlMetadata)"/>
152 /// <since_tizen> 4 </since_tizen>
153 public MediaControlMetadata GetMetadata()
157 IntPtr metadataHandle = IntPtr.Zero;
161 NativePlaylist.GetServerMetadata(Manager.Handle, ServerAppId, out metadataHandle).
162 ThrowIfError("Failed to get metadata.");
164 return new MediaControlMetadata(metadataHandle);
168 if (metadataHandle != IntPtr.Zero)
170 NativePlaylist.DestroyMetadata(metadataHandle);
176 /// Returns the all playlists.
178 /// <returns>The set of <see cref="MediaControlPlaylist"/>.</returns>
179 /// <exception cref="InvalidOperationException">
180 /// The server has already been stopped.<br/>
182 /// An internal error occurs.
184 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
185 /// <since_tizen> 5 </since_tizen>
186 public IEnumerable<MediaControlPlaylist> GetPlaylists()
190 var playlists = new List<MediaControlPlaylist>();
192 NativePlaylist.PlaylistCallback playlistCallback = (handle, _) =>
194 playlists.Add(new MediaControlPlaylist(handle));
196 NativePlaylist.ForeachServerPlaylist(Manager.Handle, ServerAppId, playlistCallback, IntPtr.Zero)
197 .ThrowIfError("Failed to get playlist.");
199 return playlists.AsReadOnly();
203 /// Returns the playlist name of current playing media.
205 /// <returns>The playlist name.</returns>
206 /// <exception cref="InvalidOperationException">
207 /// The server has already been stopped.<br/>
209 /// An internal error occurs.
211 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
212 /// <since_tizen> 5 </since_tizen>
213 public MediaControlPlaylist GetPlaylistOfCurrentPlayingMedia()
217 IntPtr playbackHandle = IntPtr.Zero;
219 // Get the playlist name of current playing media.
222 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
224 var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle);
226 return GetPlaylists().FirstOrDefault(playlist => playlist.Name == name);
230 if (playbackHandle != IntPtr.Zero)
232 Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle.");
238 /// Returns the index of current playing media.
240 /// <returns>The index of current playing media.</returns>
241 /// <exception cref="InvalidOperationException">
242 /// The server has already been stopped.<br/>
244 /// An internal error occurs.
246 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
247 /// <since_tizen> 5 </since_tizen>
248 public string GetIndexOfCurrentPlayingMedia()
252 IntPtr playbackHandle = IntPtr.Zero;
256 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
258 var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle);
263 if (playbackHandle != IntPtr.Zero)
265 Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle.");
271 /// Returns whether the shuffle mode is enabled.
273 /// <returns>A value indicating whether the shuffle mode is enabled.</returns>
274 /// <exception cref="InvalidOperationException">
275 /// The server has already been stopped.<br/>
277 /// An internal error occurs.
279 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
280 /// <seealso cref="MediaControlServer.SetShuffleModeEnabled(bool)"/>
281 /// <since_tizen> 4 </since_tizen>
282 public bool IsShuffleModeEnabled()
286 Native.GetServerShuffleMode(Manager.Handle, ServerAppId, out var shuffleMode).
287 ThrowIfError("Failed to get shuffle mode state.");
289 return shuffleMode == MediaControllerNativeShuffleMode.On;
293 /// Returns the repeat mode.
295 /// <returns>A <see cref="MediaControlRepeatMode"/> set by the server.</returns>
296 /// <exception cref="InvalidOperationException">
297 /// The server has already been stopped.<br/>
299 /// An internal error occurs.
301 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
302 /// <seealso cref="MediaControlServer.SetRepeatMode(MediaControlRepeatMode)"/>
303 /// <since_tizen> 4 </since_tizen>
304 public MediaControlRepeatMode GetRepeatMode()
308 Native.GetServerRepeatMode(Manager.Handle, ServerAppId, out var repeatMode).
309 ThrowIfError("Failed to get repeat mode state.");
311 return repeatMode.ToPublic();
315 /// Requests command to the server.
318 /// The client can request the server to execute <see cref="PlaybackCommand"/> or <see cref="ShuffleModeCommand"/> or
319 /// <see cref="RepeatModeCommand"/> or <see cref="CustomCommand"/>, <br/>
320 /// and then, the client receive the result of each request(command).
322 /// <param name="command">A <see cref="Command"/> class.</param>
323 /// <returns>A task that represents the asynchronous operation.</returns>
324 /// <exception cref="InvalidOperationException">
325 /// The server has already been stopped.<br/>
327 /// An internal error occurs.
329 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
330 /// <since_tizen> 5 </since_tizen>
331 public async Task RequestAsync(Command command)
335 command.SetRequestInformation(ServerAppId);
337 var tcs = new TaskCompletionSource<MediaControllerError>();
338 string reqeustId = null;
340 EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
342 if (e.RequestId == reqeustId)
344 tcs.TrySetResult(e.Result);
350 CommandCompleted += eventHandler;
352 reqeustId = command.Request(Manager.Handle);
354 (await tcs.Task).ThrowIfError("Failed to request command");
358 CommandCompleted -= eventHandler;
363 /// Sends the result of each command.
365 /// <param name="command">The command that return to client.</param>
366 /// <param name="result">The result of <paramref name="command"/>.</param>
367 /// <param name="bundle">The extra data.</param>
368 /// <exception cref="InvalidOperationException">
369 /// The server is not running .<br/>
371 /// An internal error occurs.
373 /// <since_tizen> 5 </since_tizen>
374 public void Response(Command command, int result, Bundle bundle)
376 command.Response(Manager.Handle, result, bundle);
380 /// Sends the result of each command.
382 /// <param name="command">The command that return to client.</param>
383 /// <param name="result">The result of <paramref name="command"/>.</param>
384 /// <exception cref="InvalidOperationException">
385 /// The server is not running .<br/>
387 /// An internal error occurs.
389 /// <since_tizen> 5 </since_tizen>
390 public void Response(Command command, int result)
392 command.Response(Manager.Handle, result, null);
396 /// Sends playback command to the server.
398 /// <param name="command">A playback command.</param>
399 /// <exception cref="InvalidOperationException">
400 /// The server has already been stopped.<br/>
402 /// An internal error occurs.
404 /// <exception cref="ArgumentException"><paramref name="command"/> is not valid.</exception>
405 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
406 /// <seealso cref="MediaControlServer.PlaybackCommandReceived"/>
407 /// <since_tizen> 4 </since_tizen>
408 [Obsolete("Please do not use! This will be deprecated. Please use Request instead.")]
409 public void SendPlaybackCommand(MediaControlPlaybackCommand command)
413 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), command, nameof(command));
415 Native.SendPlaybackStateCommand(Manager.Handle, ServerAppId, command.ToNative()).
416 ThrowIfError("Failed to send command.");
421 /// Gets the content type of current playing media.
423 /// <returns>The <see cref="MediaControlContentType"/>.</returns>
424 /// <exception cref="InvalidOperationException">
425 /// The server has already been stopped.<br/>
427 /// An internal error occurs.
429 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
430 /// <since_tizen> 5 </since_tizen>
431 public MediaControlContentType GetContentTypeOfCurrentPlayingMedia()
435 IntPtr playbackHandle = IntPtr.Zero;
439 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
441 Native.GetPlaybackContentType(playbackHandle, out MediaControlContentType type).
442 ThrowIfError("Failed to get playback content type");
448 if (playbackHandle != IntPtr.Zero)
450 Native.DestroyPlayback(playbackHandle);
456 /// Gets the icon path.
458 /// <returns>The icon path.</returns>
459 /// <exception cref="InvalidOperationException">
460 /// The server has already been stopped.<br/>
462 /// An internal error occurs.
464 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
465 /// <since_tizen> 5 </since_tizen>
466 public string GetIconPath()
470 Native.GetServerIcon(Manager.Handle, ServerAppId, out string uri).
471 ThrowIfError("Failed to get icon path.");
477 /// Gets the age rating of current playing media.
479 /// <returns>The Age rating of current playing media. The range is 0 to 19, inclusive.</returns>
480 /// <exception cref="InvalidOperationException">
481 /// The server has already been stopped.<br/>
483 /// An internal error occurs.
485 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
486 /// <since_tizen> 5 </since_tizen>
487 public int GetAgeRatingOfCurrentPlayingMedia()
491 IntPtr playbackHandle = IntPtr.Zero;
495 Native.GetServerPlayback(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback.");
497 Native.GetAgeRating(playbackHandle, out int ageRating).ThrowIfError("Failed to get age rating.");
503 if (playbackHandle != IntPtr.Zero)
505 Native.DestroyPlayback(playbackHandle);
511 /// Gets the value whether <see cref="MediaControlPlaybackCommand"/> is supported or not.
514 /// the set of <see cref="MediaControlPlaybackCommand"/> and <see cref="MediaControlCapabilitySupport"/>.
516 /// <exception cref="InvalidOperationException">
517 /// The server has already been stopped.<br/>
519 /// An internal error occurs.
521 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
522 /// <since_tizen> 5 </since_tizen>
523 public Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport> GetPlaybackCapabilities()
527 IntPtr playbackCapaHandle = IntPtr.Zero;
529 var playbackCapabilities = new Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport>();
533 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
534 ThrowIfError("Failed to get playback capability handle.");
536 foreach (MediaControllerNativePlaybackAction action in Enum.GetValues(typeof(MediaControllerNativePlaybackAction)))
538 Native.IsCapabilitySupported(playbackCapaHandle, action, out MediaControlCapabilitySupport support);
539 playbackCapabilities.Add(action.ToPublic(), support);
542 return playbackCapabilities;
546 if (playbackCapaHandle != IntPtr.Zero)
548 Native.DestroyCapability(playbackCapaHandle);
554 /// Gets the value whether <paramref name="action"/> is supported or not.
556 /// <param name="action">A playback command.</param>
557 /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
558 /// <exception cref="InvalidOperationException">
559 /// The server has already been stopped.<br/>
561 /// An internal error occurs.
563 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
564 /// <since_tizen> 5 </since_tizen>
565 public MediaControlCapabilitySupport GetPlaybackCapability(MediaControlPlaybackCommand action)
569 IntPtr playbackCapaHandle = IntPtr.Zero;
573 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
574 ThrowIfError("Failed to get playback capability handle.");
576 Native.IsCapabilitySupported(playbackCapaHandle, action.ToNative(), out MediaControlCapabilitySupport support);
582 if (playbackCapaHandle != IntPtr.Zero)
584 Native.DestroyCapability(playbackCapaHandle);
590 /// Gets the value whether the shuffle mode is supported or not.
592 /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
593 /// <exception cref="InvalidOperationException">
594 /// The server has already been stopped.<br/>
596 /// An internal error occurs.
598 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
599 /// <since_tizen> 5 </since_tizen>
600 public MediaControlCapabilitySupport GetShuffleModeCapability()
604 IntPtr playbackCapaHandle = IntPtr.Zero;
608 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
609 ThrowIfError("Failed to get playback capability handle.");
611 Native.GetShuffleCapability(Manager.Handle, ServerAppId, out MediaControlCapabilitySupport support);
617 if (playbackCapaHandle != IntPtr.Zero)
619 Native.DestroyCapability(playbackCapaHandle);
625 /// Gets the value whether the repeat mode is supported or not.
627 /// <returns>A <see cref="MediaControlCapabilitySupport"/>.</returns>
628 /// <exception cref="InvalidOperationException">
629 /// The server has already been stopped.<br/>
631 /// An internal error occurs.
633 /// <exception cref="ObjectDisposedException">The <see cref="MediaControllerManager"/> has already been disposed of.</exception>
634 /// <since_tizen> 5 </since_tizen>
635 public MediaControlCapabilitySupport GetRepeatModeCapability()
639 IntPtr playbackCapaHandle = IntPtr.Zero;
643 Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle).
644 ThrowIfError("Failed to get playback capability handle.");
646 Native.GetRepeatCapability(Manager.Handle, ServerAppId, out MediaControlCapabilitySupport support);
652 if (playbackCapaHandle != IntPtr.Zero)
654 Native.DestroyCapability(playbackCapaHandle);
658 #endregion Capabilities