/*
* 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 Tizen.Applications;
using System;
using System.Collections.Generic;
using NativeClient = Interop.MediaControllerClient;
using NativeServer = Interop.MediaControllerServer;
using NativeClientHandle = Interop.MediaControllerClientHandle;
namespace Tizen.Multimedia.Remoting
{
///
/// Provides a means to send command to media control server.
///
/// 5
public abstract class Command
{
private string _requestId;
///
/// The id for command receiver.
///
/// 5
protected string ReceiverId { get; private set; }
///
/// Initializes a base class.
///
/// 5
protected Command() { }
///
/// Sets the server information.
///
/// The receiver Id that receives command.
internal void SetRequestInformation(string receiverId)
{
ReceiverId = receiverId ?? throw new ArgumentNullException(nameof(receiverId));
}
///
/// Sets the client information.
///
/// The receiver Id that receives response for command.
/// The request Id for each command.
internal void SetResponseInformation(string receiverId, string requestId)
{
ReceiverId = receiverId ?? throw new ArgumentNullException(nameof(receiverId)); ;
_requestId = requestId ?? throw new ArgumentNullException(nameof(requestId)); ;
}
///
/// Requests command to server.
///
/// The request id for each command.
internal abstract string Request(NativeClientHandle clientHandle);
///
/// Requests command to client.
///
///
/// The request id for each command.
internal virtual string Request(IntPtr serverHandle) => throw new NotImplementedException();
///
/// Represents a method that is called when an response command completes.
///
/// 5
protected virtual void OnResponseCompleted() { }
///
/// Responses command to the client.
///
/// The server handle.
/// The result of each command.
/// The extra data.
internal void Response(IntPtr serverHandle, int result, Bundle bundle)
{
try
{
if (bundle != null)
{
NativeServer.SendCommandReplyBundle(serverHandle, ReceiverId, _requestId, result, bundle.SafeBundleHandle)
.ThrowIfError("Failed to response command.");
}
else
{
NativeServer.SendCommandReply(serverHandle, ReceiverId, _requestId, result, IntPtr.Zero)
.ThrowIfError("Failed to response command.");
}
}
catch (ArgumentException)
{
throw new InvalidOperationException("Server is not running");
}
finally
{
OnResponseCompleted();
}
}
///
/// Responses command to the server.
///
/// The client handle.
/// The result of each command.
/// The extra data.
internal void Response(NativeClientHandle clientHandle, int result, Bundle bundle)
{
try
{
if (bundle != null)
{
NativeClient.SendCustomEventReplyBundle(clientHandle, ReceiverId, _requestId, result, bundle.SafeBundleHandle)
.ThrowIfError("Failed to response event.");
}
else
{
NativeClient.SendCustomEventReply(clientHandle, ReceiverId, _requestId, result, IntPtr.Zero)
.ThrowIfError("Failed to response event.");
}
}
catch (ArgumentException)
{
throw new InvalidOperationException("Server is not running");
}
finally
{
OnResponseCompleted();
}
}
}
///
/// Provides a means to send playback command to media control server.
///
public sealed class PlaybackCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// A .
/// is not valid.
/// 5
public PlaybackCommand(MediaControlPlaybackCommand action)
{
ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
Action = action;
}
///
/// Gets the playback action.
///
/// 5
public MediaControlPlaybackCommand Action { get; }
internal override string Request(NativeClientHandle clientHandle)
{
ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), Action, nameof(Action));
NativeClient.SendPlaybackActionCommand(clientHandle, ReceiverId, Action.ToNative(), out string requestId)
.ThrowIfError("Failed to send playback command.");
return requestId;
}
}
///
/// Provides a means to send playback command to order specific time position.
///
public sealed class PlaybackPositionCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// The playback position in milliseconds.
/// 5
public PlaybackPositionCommand(ulong position)
{
Position = position;
}
///
/// Gets the position to play.
///
/// 5
public ulong Position { get; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendPlaybackPositionCommand(clientHandle, ReceiverId, Position, out string requestId)
.ThrowIfError("Failed to send playback position command.");
return requestId;
}
}
///
/// Provides a means to send playback command with playlist information.
///
public sealed class PlaylistCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// A .
/// The playlist name of the server.
/// The index of the media in the playlist.
/// The playback position in milliseconds.
/// is not valid.
///
/// or is null.
///
/// 5
public PlaylistCommand(MediaControlPlaybackCommand action, string playlistName, string index, ulong position)
{
ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
Action = action;
Index = index ?? throw new ArgumentNullException(nameof(index));
Name = playlistName ?? throw new ArgumentNullException(nameof(playlistName));
Position = position;
}
///
/// Initializes a new instance of the class.
///
/// A .
/// The playlist name of the server.
/// The index of the media in the playlist.
///
/// or is null.
///
/// 5
public PlaylistCommand(MediaControlPlaybackCommand action, string playlistName, string index)
: this(action, playlistName, index, 0)
{
}
///
/// Gets the playback action.
///
/// 5
public MediaControlPlaybackCommand Action { get; }
///
/// Gets the position to play.
///
/// 5
public ulong Position { get; }
///
/// Gets the index of playlist.
///
/// 5
public string Index { get; }
///
/// Gets the name of playlist.
///
/// 5
public string Name { get; }
internal override string Request(NativeClientHandle clientHandle)
{
ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), Action, nameof(Action));
NativeClient.SendPlaylistCommand(clientHandle, ReceiverId, Name, Index, Action.ToNative(),
Position, out string requestId).ThrowIfError("Failed to send playlist command.");
return requestId;
}
}
///
/// Provides a means to to send shuffle mode commands.
///
/// 5
public sealed class ShuffleModeCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// A shuffle mode.
/// 5
public ShuffleModeCommand(bool enabled)
{
Enabled = enabled;
}
///
/// Gets a value indicating whether the shuffle mode is enabled.
///
public bool Enabled { get; }
internal override string Request(NativeClientHandle clientHandle)
{
var mode = Enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off;
NativeClient.SendShuffleModeCommand(clientHandle, ReceiverId, mode, out string requestId).
ThrowIfError("Failed to send playback shuffle command.");
return requestId;
}
}
///
/// Provides a means to to send repeat mode commands.
///
/// 5
public sealed class RepeatModeCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// The .
/// is not valid.
/// 5
public RepeatModeCommand(MediaControlRepeatMode mode)
{
ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
Mode = mode;
}
///
/// Gets the repeat mode.
///
/// 5
public MediaControlRepeatMode Mode { get; }
internal override string Request(NativeClientHandle clientHandle)
{
ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), Mode, nameof(Mode));
NativeClient.SendRepeatModeCommand(clientHandle, ReceiverId, Mode.ToNative(), out string requestId).
ThrowIfError("Failed to send playback repeat command.");
return requestId;
}
}
///
/// Provides a means to to send subtitle mode command.
///
/// 6
public sealed class SubtitleModeCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// A value indicating whether subtitle mode is enabled.
/// 6
public SubtitleModeCommand(bool isEnabled)
{
IsEnabled = isEnabled;
}
///
/// Gets a value indicating whether subtitle mode is enabled or not.
///
/// 6
public bool IsEnabled { get; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendSubtitleModeCommand(clientHandle, ReceiverId, IsEnabled, out string requestId).
ThrowIfError("Failed to send subtitle mode command.");
return requestId;
}
}
///
/// Provides a means to to send 360 mode command.
///
/// 6
public sealed class Mode360Command : Command
{
///
/// Initializes a new instance of the class.
///
/// A value indicating whether 360 mode is enabled or not.
/// 6
public Mode360Command(bool isEnabled)
{
IsEnabled = isEnabled;
}
///
/// Gets a value indicating whether 360 mode is enabled or not.
///
/// 6
public bool IsEnabled { get; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendMode360Command(clientHandle, ReceiverId, IsEnabled, out string requestId).
ThrowIfError("Failed to send 360 mode command.");
return requestId;
}
}
///
/// Provides a means to to send display mode command.
///
/// 6
public sealed class DisplayModeCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// The .
/// is not valid.
/// 6
public DisplayModeCommand(MediaControlDisplayMode mode)
{
ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
Mode = mode;
}
///
/// Gets the display mode.
///
/// 6
public MediaControlDisplayMode Mode { get; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendDisplayModeCommand(clientHandle, ReceiverId, Mode.ToNative(), out string requestId).
ThrowIfError("Failed to send display mode command.");
return requestId;
}
}
///
/// Provides a means to to send display rotation command.
///
/// 6
public sealed class DisplayRotationCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// The .
/// is not valid.
/// 6
public DisplayRotationCommand(Rotation rotation)
{
ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
Rotation = rotation;
}
///
/// Gets the display rotation.
///
/// 6
public Rotation Rotation { get; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendDisplayRotationCommand(clientHandle, ReceiverId, Rotation.ToNative(), out string requestId).
ThrowIfError("Failed to send display rotation command.");
return requestId;
}
}
///
/// Provides a means to to send custom commands.
///
/// This command can be used by both client and server to send predefined command or data.
/// 5
public sealed class CustomCommand : Command
{
///
/// Initializes a new instance of the class.
///
/// A predefined custom command.
/// 5
public CustomCommand(string action)
{
Action = action ?? throw new ArgumentNullException(nameof(action));
}
///
/// Initializes a new instance of the class.
///
/// A predefined custom command.
/// The extra data for custom command.
/// 5
public CustomCommand(string action, Bundle bundle)
: this(action)
{
Bundle = bundle;
}
///
/// Gets the custom action.
///
/// 5
public string Action { get; }
///
/// Gets the extra data.
///
/// 5
public Bundle Bundle { get; }
internal override string Request(NativeClientHandle clientHandle)
{
string requestId = null;
if (Bundle != null)
{
NativeClient.SendCustomCommandBundle(clientHandle, ReceiverId, Action, Bundle.SafeBundleHandle, out requestId).
ThrowIfError("Failed to send custom command.");
}
else
{
NativeClient.SendCustomCommand(clientHandle, ReceiverId, Action, IntPtr.Zero, out requestId).
ThrowIfError("Failed to send custom command.");
}
return requestId;
}
internal override string Request(IntPtr serverHandle)
{
string requestId = null;
if (Bundle != null)
{
NativeServer.SendCustomEventBundle(serverHandle, ReceiverId, Action, Bundle.SafeBundleHandle, out requestId)
.ThrowIfError("Failed to send costom event.");
}
else
{
NativeServer.SendCustomEvent(serverHandle, ReceiverId, Action, IntPtr.Zero, out requestId)
.ThrowIfError("Failed to send costom event.");
}
return requestId;
}
}
///
/// Provides a means to to send search commands.
///
/// 5
public sealed class SearchCommand : Command
{
private readonly IntPtr _searchHandle;
///
/// Initializes a new instance of the class.
///
/// User can search maximum 20 items once.
/// is not set.
///
/// is greater than maximum value(20).
/// -or-
/// is less than 1.
///
/// An internal error occurs.
/// The set of .
/// 5
public SearchCommand(List conditions)
{
if (conditions == null)
{
throw new ArgumentNullException(nameof(conditions));
}
if (conditions.Count <= 0 || conditions.Count > 20)
{
var errMessage = $"Invalid number of search conditions. : {conditions.Count}. " +
$"Valid range is 1 ~ 20.";
throw new ArgumentException(errMessage);
}
NativeClient.CreateSearchHandle(out _searchHandle).ThrowIfError("Failed to create search handle.");
try
{
foreach (var condition in conditions)
{
if (condition.Bundle != null)
{
NativeClient.SetSearchConditionBundle(_searchHandle, condition.ContentType, condition.Category,
condition.Keyword, condition.Bundle.SafeBundleHandle).
ThrowIfError("Failed to set search condition.");
}
else
{
NativeClient.SetSearchCondition(_searchHandle, condition.ContentType, condition.Category,
condition.Keyword, IntPtr.Zero).
ThrowIfError("Failed to set search condition.");
}
}
}
catch
{
if (_searchHandle != IntPtr.Zero)
{
NativeClient.DestroySearchHandle(_searchHandle).ThrowIfError("Failed to destroy search handle");
}
throw;
}
}
///
/// Initializes a new instance of the class.
///
/// is not set.
/// An internal error occurs.
/// The set of .
/// 5
public SearchCommand(MediaControlSearchCondition condition)
{
if (condition == null)
{
throw new ArgumentNullException(nameof(condition));
}
NativeClient.CreateSearchHandle(out _searchHandle).ThrowIfError("Failed to create search handle.");
try
{
if (condition.Bundle != null)
{
NativeClient.SetSearchConditionBundle(_searchHandle, condition.ContentType, condition.Category,
condition.Keyword, condition.Bundle.SafeBundleHandle).
ThrowIfError("Failed to set search condition.");
}
else
{
NativeClient.SetSearchCondition(_searchHandle, condition.ContentType, condition.Category,
condition.Keyword, IntPtr.Zero).
ThrowIfError("Failed to set search condition.");
}
}
catch
{
if (_searchHandle != IntPtr.Zero)
{
NativeClient.DestroySearchHandle(_searchHandle).ThrowIfError("Failed to destroy search handle");
}
throw;
}
}
///
/// Initializes a new instance of the class by server side.
///
internal SearchCommand(List conditions, IntPtr searchHandle)
{
_searchHandle = searchHandle;
Conditions = conditions;
}
///
/// Gets or sets the search conditions.
///
/// This property is used by MediaControlServer.
/// 5
public IEnumerable Conditions { get; private set; }
internal override string Request(NativeClientHandle clientHandle)
{
NativeClient.SendSearchCommand(clientHandle, ReceiverId, _searchHandle, out string requestId).
ThrowIfError("Failed to send search command.");
return requestId;
}
///
/// Represents a method that is called when an response command completes.
///
/// 5
protected override void OnResponseCompleted()
{
base.OnResponseCompleted();
}
}
}