2 * Copyright (c) 2018 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.
17 using Tizen.Applications;
19 using System.Collections.Generic;
20 using NativeClient = Interop.MediaControllerClient;
21 using NativeServer = Interop.MediaControllerServer;
22 using NativeClientHandle = Interop.MediaControllerClientHandle;
24 namespace Tizen.Multimedia.Remoting
27 /// Provides a means to send command to media control server.
29 /// <since_tizen> 5 </since_tizen>
30 public abstract class Command
32 private string _requestId;
35 /// The id for command receiver.
37 /// <since_tizen> 5 </since_tizen>
38 protected string ReceiverId { get; private set; }
41 /// Initializes a <see cref="Command"/> base class.
43 /// <since_tizen> 5 </since_tizen>
44 protected Command() { }
47 /// Sets the server information.
49 /// <param name="receiverId">The receiver Id that receives command.</param>
50 internal void SetRequestInformation(string receiverId)
52 ReceiverId = receiverId ?? throw new ArgumentNullException(nameof(receiverId));
56 /// Sets the client information.
58 /// <param name="receiverId">The receiver Id that receives response for command.</param>
59 /// <param name="requestId">The request Id for each command.</param>
60 internal void SetResponseInformation(string receiverId, string requestId)
62 ReceiverId = receiverId ?? throw new ArgumentNullException(nameof(receiverId)); ;
63 _requestId = requestId ?? throw new ArgumentNullException(nameof(requestId)); ;
67 /// Requests command to server.
69 /// <returns>The request id for each command.</returns>
70 internal abstract string Request(NativeClientHandle clientHandle);
73 /// Requests command to client.
75 /// <param name="serverHandle"></param>
76 /// <returns>The request id for each command.</returns>
77 internal virtual string Request(IntPtr serverHandle) => throw new NotImplementedException();
80 /// Represents a method that is called when an response command completes.
82 /// <since_tizen> 5 </since_tizen>
83 protected virtual void OnResponseCompleted() { }
86 /// Responses command to the client.
88 /// <param name="serverHandle">The server handle.</param>
89 /// <param name="result">The result of each command.</param>
90 /// <param name="bundle">The extra data.</param>
91 internal void Response(IntPtr serverHandle, int result, Bundle bundle)
97 NativeServer.SendCommandReplyBundle(serverHandle, ReceiverId, _requestId, result, bundle.SafeBundleHandle)
98 .ThrowIfError("Failed to response command.");
102 NativeServer.SendCommandReply(serverHandle, ReceiverId, _requestId, result, IntPtr.Zero)
103 .ThrowIfError("Failed to response command.");
106 catch (ArgumentException)
108 throw new InvalidOperationException("Server is not running");
112 OnResponseCompleted();
117 /// Responses command to the server.
119 /// <param name="clientHandle">The client handle.</param>
120 /// <param name="result">The result of each command.</param>
121 /// <param name="bundle">The extra data.</param>
122 internal void Response(NativeClientHandle clientHandle, int result, Bundle bundle)
128 NativeClient.SendCustomEventReplyBundle(clientHandle, ReceiverId, _requestId, result, bundle.SafeBundleHandle)
129 .ThrowIfError("Failed to response event.");
133 NativeClient.SendCustomEventReply(clientHandle, ReceiverId, _requestId, result, IntPtr.Zero)
134 .ThrowIfError("Failed to response event.");
137 catch (ArgumentException)
139 throw new InvalidOperationException("Server is not running");
143 OnResponseCompleted();
150 /// Provides a means to send playback command to media control server.
152 public sealed class PlaybackCommand : Command
155 /// Initializes a new instance of the <see cref="PlaybackCommand"/> class.
157 /// <param name="action">A <see cref="MediaControlPlaybackCommand"/>.</param>
158 /// <exception cref="ArgumentException"><paramref name="action"/> is not valid.</exception>
159 /// <since_tizen> 5 </since_tizen>
160 public PlaybackCommand(MediaControlPlaybackCommand action)
162 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
168 /// Gets the playback action.
170 /// <since_tizen> 5 </since_tizen>
171 public MediaControlPlaybackCommand Action { get; }
173 internal override string Request(NativeClientHandle clientHandle)
175 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), Action, nameof(Action));
177 NativeClient.SendPlaybackActionCommand(clientHandle, ReceiverId, Action.ToNative(), out string requestId)
178 .ThrowIfError("Failed to send playback command.");
185 /// Provides a means to send playback command to order specific time position.
187 public sealed class PlaybackPositionCommand : Command
190 /// Initializes a new instance of the <see cref="PlaybackPositionCommand"/> class.
192 /// <param name="position">The playback position in milliseconds.</param>
193 /// <since_tizen> 5 </since_tizen>
194 public PlaybackPositionCommand(ulong position)
200 /// Gets the position to play.
202 /// <since_tizen> 5 </since_tizen>
203 public ulong Position { get; }
205 internal override string Request(NativeClientHandle clientHandle)
207 NativeClient.SendPlaybackPositionCommand(clientHandle, ReceiverId, Position, out string requestId)
208 .ThrowIfError("Failed to send playback position command.");
215 /// Provides a means to send playback command with playlist information.
217 public sealed class PlaylistCommand : Command
220 /// Initializes a new instance of the <see cref="PlaybackCommand"/> class.
222 /// <param name="action">A <see cref="MediaControlPlaybackCommand"/>.</param>
223 /// <param name="playlistName">The playlist name of the server.</param>
224 /// <param name="index">The index of the media in the playlist.</param>
225 /// <param name="position">The playback position in milliseconds.</param>
226 /// <exception cref="ArgumentException"><paramref name="action"/>is not valid.</exception>
227 /// <exception cref="ArgumentNullException">
228 /// <paramref name="playlistName"/> or <paramref name="index"/> is null.
230 /// <since_tizen> 5 </since_tizen>
231 public PlaylistCommand(MediaControlPlaybackCommand action, string playlistName, string index, ulong position)
233 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
236 Index = index ?? throw new ArgumentNullException(nameof(index));
237 Name = playlistName ?? throw new ArgumentNullException(nameof(playlistName));
242 /// Initializes a new instance of the <see cref="PlaybackCommand"/> class.
244 /// <param name="action">A <see cref="MediaControlPlaybackCommand"/>.</param>
245 /// <param name="playlistName">The playlist name of the server.</param>
246 /// <param name="index">The index of the media in the playlist.</param>
247 /// <exception cref="ArgumentNullException">
248 /// <paramref name="playlistName"/> or <paramref name="index"/> is null.
250 /// <since_tizen> 5 </since_tizen>
251 public PlaylistCommand(MediaControlPlaybackCommand action, string playlistName, string index)
252 : this(action, playlistName, index, 0)
257 /// Gets the playback action.
259 /// <since_tizen> 5 </since_tizen>
260 public MediaControlPlaybackCommand Action { get; }
263 /// Gets the position to play.
265 /// <since_tizen> 5 </since_tizen>
266 public ulong Position { get; }
269 /// Gets the index of playlist.
271 /// <since_tizen> 5 </since_tizen>
272 public string Index { get; }
275 /// Gets the name of playlist.
277 /// <since_tizen> 5 </since_tizen>
278 public string Name { get; }
280 internal override string Request(NativeClientHandle clientHandle)
282 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), Action, nameof(Action));
284 NativeClient.SendPlaylistCommand(clientHandle, ReceiverId, Name, Index, Action.ToNative(),
285 Position, out string requestId).ThrowIfError("Failed to send playlist command.");
292 /// Provides a means to to send shuffle mode commands.
294 /// <since_tizen> 5 </since_tizen>
295 public sealed class ShuffleModeCommand : Command
298 /// Initializes a new instance of the <see cref="ShuffleModeCommand"/> class.
300 /// <param name="enabled">A shuffle mode.</param>
301 /// <since_tizen> 5 </since_tizen>
302 public ShuffleModeCommand(bool enabled)
308 /// Gets a value indicating whether the shuffle mode is enabled.
310 public bool Enabled { get; }
312 internal override string Request(NativeClientHandle clientHandle)
314 var mode = Enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off;
316 NativeClient.SendShuffleModeCommand(clientHandle, ReceiverId, mode, out string requestId).
317 ThrowIfError("Failed to send playback shuffle command.");
324 /// Provides a means to to send repeat mode commands.
326 /// <since_tizen> 5 </since_tizen>
327 public sealed class RepeatModeCommand : Command
330 /// Initializes a new instance of the <see cref="RepeatModeCommand"/> class.
332 /// <param name="mode">The <see cref="MediaControlRepeatMode"/>.</param>
333 /// <exception cref="ArgumentException"><paramref name="mode"/> is not valid.</exception>
334 /// <since_tizen> 5 </since_tizen>
335 public RepeatModeCommand(MediaControlRepeatMode mode)
337 ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
343 /// Gets the repeat mode.
345 /// <since_tizen> 5 </since_tizen>
346 public MediaControlRepeatMode Mode { get; }
348 internal override string Request(NativeClientHandle clientHandle)
350 ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), Mode, nameof(Mode));
352 NativeClient.SendRepeatModeCommand(clientHandle, ReceiverId, Mode.ToNative(), out string requestId).
353 ThrowIfError("Failed to send playback repeat command.");
360 /// Provides a means to to send subtitle mode command.
362 /// <since_tizen> 6 </since_tizen>
363 public sealed class SubtitleModeCommand : Command
366 /// Initializes a new instance of the <see cref="SubtitleModeCommand"/> class.
368 /// <param name="isEnabled">A value indicating whether subtitle mode is enabled.</param>
369 /// <since_tizen> 6 </since_tizen>
370 public SubtitleModeCommand(bool isEnabled)
372 IsEnabled = isEnabled;
376 /// Gets a value indicating whether subtitle mode is enabled or not.
378 /// <since_tizen> 6 </since_tizen>
379 public bool IsEnabled { get; }
381 internal override string Request(NativeClientHandle clientHandle)
383 NativeClient.SendSubtitleModeCommand(clientHandle, ReceiverId, IsEnabled, out string requestId).
384 ThrowIfError("Failed to send subtitle mode command.");
391 /// Provides a means to to send 360 mode command.
393 /// <since_tizen> 6 </since_tizen>
394 public sealed class Mode360Command : Command
397 /// Initializes a new instance of the <see cref="Mode360Command"/> class.
399 /// <param name="isEnabled">A value indicating whether 360 mode is enabled or not.</param>
400 /// <since_tizen> 6 </since_tizen>
401 public Mode360Command(bool isEnabled)
403 IsEnabled = isEnabled;
407 /// Gets a value indicating whether 360 mode is enabled or not.
409 /// <since_tizen> 6 </since_tizen>
410 public bool IsEnabled { get; }
412 internal override string Request(NativeClientHandle clientHandle)
414 NativeClient.SendMode360Command(clientHandle, ReceiverId, IsEnabled, out string requestId).
415 ThrowIfError("Failed to send 360 mode command.");
422 /// Provides a means to to send display mode command.
424 /// <since_tizen> 6 </since_tizen>
425 public sealed class DisplayModeCommand : Command
428 /// Initializes a new instance of the <see cref="DisplayModeCommand"/> class.
430 /// <param name="mode">The <see cref="MediaControlDisplayMode"/>.</param>
431 /// <exception cref="ArgumentException"><paramref name="mode"/> is not valid.</exception>
432 /// <since_tizen> 6 </since_tizen>
433 public DisplayModeCommand(MediaControlDisplayMode mode)
435 ValidationUtil.ValidateEnum(typeof(MediaControlDisplayMode), mode, nameof(mode));
441 /// Gets the display mode.
443 /// <since_tizen> 6 </since_tizen>
444 public MediaControlDisplayMode Mode { get; }
446 internal override string Request(NativeClientHandle clientHandle)
448 NativeClient.SendDisplayModeCommand(clientHandle, ReceiverId, Mode.ToNative(), out string requestId).
449 ThrowIfError("Failed to send display mode command.");
456 /// Provides a means to to send display rotation command.
458 /// <since_tizen> 6 </since_tizen>
459 public sealed class DisplayRotationCommand : Command
462 /// Initializes a new instance of the <see cref="DisplayRotationCommand"/> class.
464 /// <param name="rotation">The <see cref="Rotation"/>.</param>
465 /// <exception cref="ArgumentException"><paramref name="rotation"/> is not valid.</exception>
466 /// <since_tizen> 6 </since_tizen>
467 public DisplayRotationCommand(Rotation rotation)
469 ValidationUtil.ValidateEnum(typeof(Rotation), rotation, nameof(rotation));
475 /// Gets the display rotation.
477 /// <since_tizen> 6 </since_tizen>
478 public Rotation Rotation { get; }
480 internal override string Request(NativeClientHandle clientHandle)
482 NativeClient.SendDisplayRotationCommand(clientHandle, ReceiverId, Rotation.ToNative(), out string requestId).
483 ThrowIfError("Failed to send display rotation command.");
490 /// Provides a means to to send custom commands.
492 /// <remarks>This command can be used by both client and server to send predefined command or data.</remarks>
493 /// <since_tizen> 5 </since_tizen>
494 public sealed class CustomCommand : Command
497 /// Initializes a new instance of the <see cref="CustomCommand"/> class.
499 /// <param name="action">A predefined custom command.</param>
500 /// <since_tizen> 5 </since_tizen>
501 public CustomCommand(string action)
503 Action = action ?? throw new ArgumentNullException(nameof(action));
507 /// Initializes a new instance of the <see cref="CustomCommand"/> class.
509 /// <param name="action">A predefined custom command.</param>
510 /// <param name="bundle">The extra data for custom command.</param>
511 /// <since_tizen> 5 </since_tizen>
512 public CustomCommand(string action, Bundle bundle)
519 /// Gets the custom action.
521 /// <since_tizen> 5 </since_tizen>
522 public string Action { get; }
525 /// Gets the extra data.
527 /// <since_tizen> 5 </since_tizen>
528 public Bundle Bundle { get; }
530 internal override string Request(NativeClientHandle clientHandle)
532 string requestId = null;
536 NativeClient.SendCustomCommandBundle(clientHandle, ReceiverId, Action, Bundle.SafeBundleHandle, out requestId).
537 ThrowIfError("Failed to send custom command.");
541 NativeClient.SendCustomCommand(clientHandle, ReceiverId, Action, IntPtr.Zero, out requestId).
542 ThrowIfError("Failed to send custom command.");
548 internal override string Request(IntPtr serverHandle)
550 string requestId = null;
554 NativeServer.SendCustomEventBundle(serverHandle, ReceiverId, Action, Bundle.SafeBundleHandle, out requestId)
555 .ThrowIfError("Failed to send costom event.");
559 NativeServer.SendCustomEvent(serverHandle, ReceiverId, Action, IntPtr.Zero, out requestId)
560 .ThrowIfError("Failed to send costom event.");
568 /// Provides a means to to send search commands.
570 /// <since_tizen> 5 </since_tizen>
571 public sealed class SearchCommand : Command
573 private readonly IntPtr _searchHandle;
576 /// Initializes a new instance of the <see cref="SearchCommand"/> class.
578 /// <remarks>User can search maximum 20 items once.</remarks>
579 /// <exception cref="ArgumentNullException"><paramref name="conditions"/> is not set.</exception>
580 /// <exception cref="ArgumentException">
581 /// <paramref name="conditions.Count"/> is greater than maximum value(20).<br/>
583 /// <paramref name="conditions.Count"/> is less than 1.
585 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
586 /// <param name="conditions">The set of <see cref="MediaControlSearchCondition"/>.</param>
587 /// <since_tizen> 5 </since_tizen>
588 public SearchCommand(List<MediaControlSearchCondition> conditions)
590 if (conditions == null)
592 throw new ArgumentNullException(nameof(conditions));
594 if (conditions.Count <= 0 || conditions.Count > 20)
596 var errMessage = $"Invalid number of search conditions. : {conditions.Count}. " +
597 $"Valid range is 1 ~ 20.";
598 throw new ArgumentException(errMessage);
601 NativeClient.CreateSearchHandle(out _searchHandle).ThrowIfError("Failed to create search handle.");
605 foreach (var condition in conditions)
607 if (condition.Bundle != null)
609 NativeClient.SetSearchConditionBundle(_searchHandle, condition.ContentType, condition.Category,
610 condition.Keyword, condition.Bundle.SafeBundleHandle).
611 ThrowIfError("Failed to set search condition.");
615 NativeClient.SetSearchCondition(_searchHandle, condition.ContentType, condition.Category,
616 condition.Keyword, IntPtr.Zero).
617 ThrowIfError("Failed to set search condition.");
623 if (_searchHandle != IntPtr.Zero)
625 NativeClient.DestroySearchHandle(_searchHandle).ThrowIfError("Failed to destroy search handle");
632 /// Initializes a new instance of the <see cref="SearchCommand"/> class.
634 /// <exception cref="ArgumentNullException"><paramref name="condition"/> is not set.</exception>
635 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
636 /// <param name="condition">The set of <see cref="MediaControlSearchCondition"/>.</param>
637 /// <since_tizen> 5 </since_tizen>
638 public SearchCommand(MediaControlSearchCondition condition)
640 if (condition == null)
642 throw new ArgumentNullException(nameof(condition));
645 NativeClient.CreateSearchHandle(out _searchHandle).ThrowIfError("Failed to create search handle.");
649 if (condition.Bundle != null)
651 NativeClient.SetSearchConditionBundle(_searchHandle, condition.ContentType, condition.Category,
652 condition.Keyword, condition.Bundle.SafeBundleHandle).
653 ThrowIfError("Failed to set search condition.");
657 NativeClient.SetSearchCondition(_searchHandle, condition.ContentType, condition.Category,
658 condition.Keyword, IntPtr.Zero).
659 ThrowIfError("Failed to set search condition.");
664 if (_searchHandle != IntPtr.Zero)
666 NativeClient.DestroySearchHandle(_searchHandle).ThrowIfError("Failed to destroy search handle");
673 /// Initializes a new instance of the <see cref="SearchCommand"/> class by server side.
675 internal SearchCommand(List<MediaControlSearchCondition> conditions, IntPtr searchHandle)
677 _searchHandle = searchHandle;
678 Conditions = conditions;
682 /// Gets or sets the search conditions.
684 /// <remarks>This property is used by MediaControlServer.</remarks>
685 /// <since_tizen> 5 </since_tizen>
686 public IEnumerable<MediaControlSearchCondition> Conditions { get; private set; }
688 internal override string Request(NativeClientHandle clientHandle)
690 NativeClient.SendSearchCommand(clientHandle, ReceiverId, _searchHandle, out string requestId).
691 ThrowIfError("Failed to send search command.");
697 /// Represents a method that is called when an response command completes.
699 /// <since_tizen> 5 </since_tizen>
700 protected override void OnResponseCompleted()
702 base.OnResponseCompleted();