/* * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Linq; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using Tizen.Applications; using Native = Interop.MediaControllerClient; using NativePlaylist = Interop.MediaControllerPlaylist; namespace Tizen.Multimedia.Remoting { /// /// Provides a means to send commands to and handle events from media control server. /// /// 4 public partial class MediaController { internal MediaController(MediaControllerManager manager, string serverAppId) { Debug.Assert(manager != null); Debug.Assert(serverAppId != null); Manager = manager; ServerAppId = serverAppId; } private MediaControllerManager Manager { get; } /// /// Gets the application id of the server. /// /// The server application id. /// 4 public string ServerAppId { get; } /// /// Gets a value indicating whether the sever has been stopped. /// /// true if the server has been stopped; otherwise, false. /// 4 public bool IsStopped { get; private set; } private void ThrowIfStopped() { if (IsStopped) { throw new InvalidOperationException("The server has already been stopped."); } } #region Get information /// /// Returns the playback state set by the server. /// /// The playback state. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// 4 public MediaControlPlaybackState GetPlaybackState() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); Native.GetPlaybackState(playbackHandle, out var playbackCode).ThrowIfError("Failed to get state."); return playbackCode.ToPublic(); } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle); } } } /// /// Returns the playback position set by the server. /// /// The playback position in milliseconds. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// 4 public long GetPlaybackPosition() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); Native.GetPlaybackPosition(playbackHandle, out var position).ThrowIfError("Failed to get position."); return (long)position; } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle); } } } /// /// Returns the metadata set by the server. /// /// The metadata. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// 4 public MediaControlMetadata GetMetadata() { ThrowIfStopped(); IntPtr metadataHandle = IntPtr.Zero; try { NativePlaylist.GetServerMetadata(Manager.Handle, ServerAppId, out metadataHandle). ThrowIfError("Failed to get metadata."); return new MediaControlMetadata(metadataHandle); } finally { if (metadataHandle != IntPtr.Zero) { NativePlaylist.DestroyMetadata(metadataHandle); } } } /// /// Returns the all playlists. /// /// The set of . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public IEnumerable GetPlaylists() { ThrowIfStopped(); var playlists = new List(); Exception caught = null; NativePlaylist.PlaylistCallback playlistCallback = (handle, _) => { try { playlists.Add(new MediaControlPlaylist(handle)); return true; } catch (Exception e) { caught = e; return false; } }; NativePlaylist.ForeachPlaylist(ServerAppId, playlistCallback, IntPtr.Zero). ThrowIfError("Failed to get playlist."); if (caught != null) { throw caught; } return playlists.AsReadOnly(); } /// /// Returns the playlist name of current playing media. /// /// The playlist name. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public MediaControlPlaylist GetPlaylistOfCurrentPlayingMedia() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; // Get the playlist name of current playing media. try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle); return GetPlaylists().FirstOrDefault(playlist => playlist.Name == name); } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle."); } } } /// /// Returns the index of current playing media. /// /// The index of current playing media. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public string GetIndexOfCurrentPlayingMedia() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); var (name, index) = NativePlaylist.GetPlaylistInfo(playbackHandle); return index; } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle).ThrowIfError("Failed to destroy playback handle."); } } } /// /// Returns whether the shuffle mode is enabled. /// /// A value indicating whether the shuffle mode is enabled. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// 4 public bool IsShuffleModeEnabled() { ThrowIfStopped(); Native.GetServerShuffleMode(Manager.Handle, ServerAppId, out var shuffleMode). ThrowIfError("Failed to get shuffle mode state."); return shuffleMode == MediaControllerNativeShuffleMode.On; } /// /// Returns the repeat mode. /// /// A set by the server. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// 4 public MediaControlRepeatMode GetRepeatMode() { ThrowIfStopped(); Native.GetServerRepeatMode(Manager.Handle, ServerAppId, out var repeatMode). ThrowIfError("Failed to get repeat mode state."); return repeatMode.ToPublic(); } /// /// Gets the content type of current playing media. /// /// The . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public MediaControlContentType GetContentTypeOfCurrentPlayingMedia() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); Native.GetPlaybackContentType(playbackHandle, out MediaControlContentType type). ThrowIfError("Failed to get playback content type"); return type; } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle); } } } /// /// Gets the icon path. /// /// The icon path. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public string GetIconPath() { ThrowIfStopped(); Native.GetServerIcon(Manager.Handle, ServerAppId, out string uri). ThrowIfError("Failed to get icon path."); return uri; } /// /// Gets the age rating of current playing media. /// /// The Age rating of current playing media. The range is 0 to 19, inclusive. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public int GetAgeRatingOfCurrentPlayingMedia() { ThrowIfStopped(); IntPtr playbackHandle = IntPtr.Zero; try { Native.GetServerPlaybackHandle(Manager.Handle, ServerAppId, out playbackHandle).ThrowIfError("Failed to get playback."); Native.GetAgeRating(playbackHandle, out int ageRating).ThrowIfError("Failed to get age rating."); return ageRating; } finally { if (playbackHandle != IntPtr.Zero) { Native.DestroyPlayback(playbackHandle); } } } /// /// Gets whether the subtitle mode is enabled or not. /// /// A value indicating whether the subtitle mode is enabled or not. /// true if the subtitle mode is enabled; otherwise, false. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public bool IsSubtitleModeEnabled() { ThrowIfStopped(); Native.IsSubtitleEnabled(Manager.Handle, ServerAppId, out var isEnabled). ThrowIfError("Failed to get subtitle mode state."); return isEnabled; } /// /// Gets whether the 360 mode is enabled or not. /// /// A value indicating whether the 360 mode is enabled or not. /// true if the 360 mode is enabled; otherwise, false. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public bool IsMode360Enabled() { ThrowIfStopped(); Native.IsMode360Enabled(Manager.Handle, ServerAppId, out var isEnabled). ThrowIfError("Failed to get 360 mode state."); return isEnabled; } /// /// Gets the current display mode. /// /// The . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// /// The has already been disposed. /// /// 6 public MediaControlDisplayMode GetDisplayMode() { ThrowIfStopped(); Native.GetDisplayMode(Manager.Handle, ServerAppId, out var mode). ThrowIfError("Failed to get display mode state."); return mode.ToPublic(); } /// /// Gets the current display rotation. /// /// The . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// /// The has already been disposed. /// /// 6 public Rotation GetDisplayRotation() { ThrowIfStopped(); Native.GetDisplayRotation(Manager.Handle, ServerAppId, out var rotation). ThrowIfError("Failed to get display rotation state."); return rotation.ToPublic(); } #endregion Get information #region Capability /// /// Gets the value whether is supported or not. /// /// /// the set of and . /// /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public Dictionary GetPlaybackCapabilities() { ThrowIfStopped(); IntPtr playbackCapaHandle = IntPtr.Zero; var playbackCapabilities = new Dictionary(); try { Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle). ThrowIfError("Failed to get playback capability handle."); foreach (MediaControllerNativePlaybackAction action in Enum.GetValues(typeof(MediaControllerNativePlaybackAction))) { Native.GetPlaybackCapability(playbackCapaHandle, action, out MediaControlCapabilitySupport support); playbackCapabilities.Add(action.ToPublic(), support); } return playbackCapabilities; } finally { if (playbackCapaHandle != IntPtr.Zero) { Native.DestroyCapability(playbackCapaHandle); } } } /// /// Gets the value whether is supported or not. /// /// A playback command. /// A . /// is not valid. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public MediaControlCapabilitySupport GetPlaybackCapability(MediaControlPlaybackCommand action) { ThrowIfStopped(); ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action)); IntPtr playbackCapaHandle = IntPtr.Zero; try { Native.GetPlaybackCapabilityHandle(Manager.Handle, ServerAppId, out playbackCapaHandle). ThrowIfError("Failed to get playback capability handle."); Native.GetPlaybackCapability(playbackCapaHandle, action.ToNative(), out MediaControlCapabilitySupport support); return support; } finally { if (playbackCapaHandle != IntPtr.Zero) { Native.DestroyCapability(playbackCapaHandle); } } } /// /// Gets the value whether the shuffle mode is supported or not. /// /// A . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public MediaControlCapabilitySupport GetShuffleModeCapability() { ThrowIfStopped(); Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Shuffle, out MediaControlCapabilitySupport support). ThrowIfError("Failed to get shuffle mode capability"); return support; } /// /// Gets the value whether the repeat mode is supported or not. /// /// A . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 5 public MediaControlCapabilitySupport GetRepeatModeCapability() { ThrowIfStopped(); Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Repeat, out MediaControlCapabilitySupport support). ThrowIfError("Failed to get repeat mode capability"); return support; } /// /// Gets the value whether the 360 mode is supported or not. /// /// A . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public MediaControlCapabilitySupport GetMode360Capability() { ThrowIfStopped(); Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Mode360, out MediaControlCapabilitySupport support). ThrowIfError("Failed to get 360 mode capability"); return support; } /// /// Gets the value whether the subtitle mode is supported or not. /// /// A . /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public MediaControlCapabilitySupport GetSubtitleModeCapability() { ThrowIfStopped(); Native.GetSimpleCapability(Manager.Handle, ServerAppId, MediaControlNativeCapabilityCategory.Subtitle, out MediaControlCapabilitySupport support). ThrowIfError("Failed to get subtitle mode capability"); return support; } /// /// Gets the value whether the repeat mode is supported or not. /// /// /// If there's no supported display mode by server, it will return null. /// otherwise, it will return the supported list of . /// /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public IEnumerable GetDisplayModeCapability() { ThrowIfStopped(); Native.GetDisplayModeCapability(Manager.Handle, ServerAppId, out uint support). ThrowIfError("Failed to get display mode capability"); return support != 0 ? ((MediaControlNativeDisplayMode)support).ToPublicList() : null; } /// /// Gets the value whether the display mode is supported or not. /// /// /// If there's no supported display rotation by server, it will return null. /// otherwise, it will return the supported list of . /// /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// 6 public IEnumerable GetDisplayRotationCapability() { ThrowIfStopped(); Native.GetDisplayRotationCapability(Manager.Handle, ServerAppId, out uint support). ThrowIfError("Failed to get display mode capability"); return support != 0 ? ((MediaControlNativeDisplayRotation)support).ToPublicList() : null; } #endregion Capability #region Command /// /// Requests a command to the server and client receives the result of each request(command). /// /// A class. /// /// The type of return value is Tuple.
/// First item of Tuple represents the and it represents the extra data from client. It can be null.
/// Second item of Tuple represents the result of each request(command). ///
/// is null. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// /// /// /// /// /// /// /// /// /// /// 8 public async Task<(Bundle bundle, int result)> RequestCommandAsync(Command command) { if (command == null) { throw new ArgumentNullException(nameof(command)); } ThrowIfStopped(); command.SetRequestInformation(ServerAppId); var tcs = new TaskCompletionSource(); string reqeustId = null; Bundle bundle = null; EventHandler eventHandler = (s, e) => { if (e.RequestId == reqeustId) { bundle = e.Bundle; tcs.TrySetResult(e.Result); } }; try { CommandCompleted += eventHandler; reqeustId = command.Request(Manager.Handle); var result = await tcs.Task; return (bundle, result); } finally { CommandCompleted -= eventHandler; } } /// /// Requests command to the server. /// /// A class. /// represents the extra data from server and it can be null. /// is null. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// /// /// /// /// /// /// /// /// /// /// 5 [Obsolete("Deprecated since API8; Will be removed in API10. Please use RequestCommandAsync(Command command) instead.")] public async Task RequestAsync(Command command) { if (command == null) { throw new ArgumentNullException(nameof(command)); } ThrowIfStopped(); command.SetRequestInformation(ServerAppId); var tcs = new TaskCompletionSource(); string reqeustId = null; Bundle bundle = null; EventHandler eventHandler = (s, e) => { if (e.RequestId == reqeustId) { bundle = e.Bundle; tcs.TrySetResult(e.Result); } }; try { CommandCompleted += eventHandler; reqeustId = command.Request(Manager.Handle); ((MediaControllerError)await tcs.Task).ThrowIfError("Failed to request command"); return bundle; } finally { CommandCompleted -= eventHandler; } } /// /// Sends the result of each command. /// /// The command that return to client. /// The result of . /// The extra data. /// is null. /// /// The server is not running .
/// -or-
/// An internal error occurs. ///
/// 5 public void Response(Command command, int result, Bundle bundle) { if (command == null) { throw new ArgumentNullException(nameof(command)); } command.Response(Manager.Handle, result, bundle); } /// /// Sends the result of each command. /// /// The command that return to client. /// The result of . /// is null. /// /// The server is not running .
/// -or-
/// An internal error occurs. ///
/// 5 public void Response(Command command, int result) { Response(command, result, null); } /// /// Sends the result of each command. /// /// The command that return to client. /// The of . /// The extra data. /// is null. /// /// The server is not running .
/// -or-
/// An internal error occurs. ///
/// 8 public void Response(Command command, MediaControlResult result, Bundle bundle) { Response(command, (int)result, bundle); } /// /// Sends the result of each command. /// /// The command that return to client. /// The of . /// is null. /// /// The server is not running .
/// -or-
/// An internal error occurs. ///
/// 8 public void Response(Command command, MediaControlResult result) { Response(command, (int)result, null); } /// /// Sends playback command to the server. /// /// A playback command. /// /// The server has already been stopped.
/// -or-
/// An internal error occurs. ///
/// is not valid. /// The has already been disposed. /// /// 4 [Obsolete("Please do not use! This will be deprecated. Please use Request instead.")] public void SendPlaybackCommand(MediaControlPlaybackCommand command) { ThrowIfStopped(); ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), command, nameof(command)); Native.SendPlaybackActionCommandWithoutReqId(Manager.Handle, ServerAppId, command.ToNative()). ThrowIfError("Failed to send command."); } #endregion Command } }