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.
18 using System.Collections.Generic;
19 using System.Threading.Tasks;
20 using Tizen.Applications;
21 using Native = Interop.MediaControllerServer;
23 namespace Tizen.Multimedia.Remoting
26 /// Provides a means to set playback information and metadata and receive commands from clients.
28 /// <seealso cref="MediaControllerManager"/>
29 /// <seealso cref="MediaController"/>
30 /// <since_tizen> 4 </since_tizen>
31 public static partial class MediaControlServer
33 private static IntPtr _handle = IntPtr.Zero;
34 private static bool? _isRunning;
37 /// Gets a value indicating whether the server is running.
39 /// <value>true if the server has started; otherwise, false.</value>
40 /// <seealso cref="Start"/>
41 /// <seealso cref="Stop"/>
42 /// <since_tizen> 4 </since_tizen>
43 public static bool IsRunning
47 if (_isRunning.HasValue == false)
49 _isRunning = GetRunningState();
52 return _isRunning.Value;
56 private static bool GetRunningState()
58 IntPtr handle = IntPtr.Zero;
61 Native.ConnectDb(out handle).ThrowIfError("Failed to retrieve the running state.");
63 Native.CheckServerExist(handle, Applications.Application.Current.ApplicationInfo.ApplicationId,
64 out var value).ThrowIfError("Failed to retrieve the running state.");
70 if (handle != IntPtr.Zero)
72 Native.DisconnectDb(handle);
77 private static void EnsureInitializedIfRunning()
79 if (_handle != IntPtr.Zero)
84 if (IsRunning == false)
86 throw new InvalidOperationException("The server is not running.");
92 private static IntPtr Handle
96 EnsureInitializedIfRunning();
102 private static void Initialize()
104 Native.Create(out _handle).ThrowIfError("Failed to create media controller server.");
108 RegisterPlaybackCommandReceivedEvent();
109 RegisterPlaybackActionCommandReceivedEvent();
110 RegisterPlaybackPositionCommandReceivedEvent();
111 RegisterPlaylistCommandReceivedEvent();
112 RegisterShuffleModeCommandReceivedEvent();
113 RegisterRepeatModeCommandReceivedEvent();
114 RegisterCustomCommandReceivedEvent();
115 RegisterCommandCompletedEvent();
116 RegisterSearchCommandReceivedEvent();
122 Native.Destroy(_handle);
123 _playbackCommandCallback = null;
124 _handle = IntPtr.Zero;
130 /// Starts the media control server.
133 /// When the server starts, <see cref="MediaControllerManager.ServerStarted"/> will be raised.
135 /// <privilege>http://tizen.org/privilege/mediacontroller.server</privilege>
136 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
137 /// <exception cref="UnauthorizedAccessException">Caller does not have required privilege.</exception>
138 /// <seealso cref="MediaControllerManager.ServerStarted"/>
139 /// <since_tizen> 4 </since_tizen>
140 public static void Start()
146 /// Stops the media control server.
149 /// When the server stops, <see cref="MediaControllerManager.ServerStopped"/> will be raised.
151 /// <exception cref="InvalidOperationException">
152 /// The server is not running .<br/>
154 /// An internal error occurs.
156 /// <seealso cref="MediaControllerManager.ServerStopped"/>
157 /// <since_tizen> 4 </since_tizen>
158 public static void Stop()
160 EnsureInitializedIfRunning();
162 Native.Destroy(_handle).ThrowIfError("Failed to stop the server.");
164 _handle = IntPtr.Zero;
165 _playbackCommandCallback = null;
170 /// Updates playback state and playback position.</summary>
171 /// <param name="state">The playback state.</param>
172 /// <param name="position">The playback position in milliseconds.</param>
173 /// <exception cref="ArgumentException"><paramref name="state"/> is not valid.</exception>
174 /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero.</exception>
175 /// <exception cref="InvalidOperationException">
176 /// The server is not running .<br/>
178 /// An internal error occurs.
180 /// <since_tizen> 4 </since_tizen>
181 public static void SetPlaybackState(MediaControlPlaybackState state, long position)
183 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackState), state, nameof(state));
187 throw new ArgumentOutOfRangeException(nameof(position), position, "position can't be less than zero.");
190 Native.SetPlaybackState(Handle, state.ToNative()).ThrowIfError("Failed to set playback state.");
192 Native.SetPlaybackPosition(Handle, (ulong)position).ThrowIfError("Failed to set playback position.");
194 Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
197 private static void SetMetadata(MediaControllerNativeAttribute attribute, string value)
199 Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
203 /// Updates metadata information.
205 /// <param name="metadata">The metadata to update.</param>
206 /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception>
207 /// <exception cref="InvalidOperationException">
208 /// The server is not running .<br/>
210 /// An internal error occurs.
212 /// <since_tizen> 4 </since_tizen>
213 public static void SetMetadata(MediaControlMetadata metadata)
215 if (metadata == null)
217 throw new ArgumentNullException(nameof(metadata));
220 SetMetadata(MediaControllerNativeAttribute.Title, metadata.Title);
221 SetMetadata(MediaControllerNativeAttribute.Artist, metadata.Artist);
222 SetMetadata(MediaControllerNativeAttribute.Album, metadata.Album);
223 SetMetadata(MediaControllerNativeAttribute.Author, metadata.Author);
224 SetMetadata(MediaControllerNativeAttribute.Genre, metadata.Genre);
225 SetMetadata(MediaControllerNativeAttribute.Duration, metadata.Duration);
226 SetMetadata(MediaControllerNativeAttribute.Date, metadata.Date);
227 SetMetadata(MediaControllerNativeAttribute.Copyright, metadata.Copyright);
228 SetMetadata(MediaControllerNativeAttribute.Description, metadata.Description);
229 SetMetadata(MediaControllerNativeAttribute.TrackNumber, metadata.TrackNumber);
230 SetMetadata(MediaControllerNativeAttribute.Picture, metadata.AlbumArtPath);
232 Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
236 /// Updates the shuffle mode.
238 /// <param name="enabled">A value indicating whether the shuffle mode is enabled.</param>
239 /// <exception cref="InvalidOperationException">
240 /// The server is not running .<br/>
242 /// An internal error occurs.
244 /// <since_tizen> 4 </since_tizen>
245 public static void SetShuffleModeEnabled(bool enabled)
247 Native.UpdateShuffleMode(Handle, enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off).
248 ThrowIfError("Failed to set shuffle mode.");
252 /// Updates the repeat mode.
254 /// <param name="mode">A value indicating the repeat mode.</param>
255 /// <exception cref="InvalidOperationException">
256 /// The server is not running .<br/>
258 /// An internal error occurs.
260 /// <exception cref="ArgumentException"><paramref name="mode"/> is invalid.</exception>
261 /// <since_tizen> 4 </since_tizen>
262 public static void SetRepeatMode(MediaControlRepeatMode mode)
264 ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
266 Native.UpdateRepeatMode(Handle, mode.ToNative()).ThrowIfError("Failed to set repeat mode.");
270 /// Sets the index of current playing media.
272 /// <param name="index">The index of current playing media.</param>
273 /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
274 /// <exception cref="InvalidOperationException">
275 /// The server is not running .<br/>
277 /// An internal error occurs.
279 /// <since_tizen> 5 </since_tizen>
280 public static void SetIndexOfCurrentPlayingMedia(string index)
282 Native.SetIndexOfCurrentPlayingMedia(Handle, index)
283 .ThrowIfError("Failed to set the index of current playing media");
289 /// <param name="playlist">The name of playlist.</param>
290 /// <exception cref="InvalidOperationException">
291 /// The server is not running .<br/>
293 /// An internal error occurs.
295 /// <since_tizen> 5 </since_tizen>
296 public static void RemovePlaylist(MediaControlPlaylist playlist)
298 Native.DeletePlaylist(Handle, playlist.Handle);
302 // Saves the playlist to the persistent storage.
303 internal static void SavePlaylist(IntPtr playlistHandle)
305 Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
308 // Gets the playlist handle by name.
309 internal static IntPtr GetPlaylistHandle(string name)
311 Native.GetPlaylistHandle(Handle, name, out IntPtr playlistHandle)
312 .ThrowIfError("Failed to get playlist handle by name");
314 return playlistHandle;
318 /// Gets the active clients.
320 /// <exception cref="InvalidOperationException">
321 /// The server is not running .<br/>
323 /// An internal error occurs.
325 /// <returns>the activated client ids.</returns>
326 /// <since_tizen> 5 </since_tizen>
327 public static IEnumerable<string> GetActivatedClients()
329 var clientIds = new List<string>();
331 Native.ActivatedClientCallback activatedClientCallback = (name, _) =>
337 Native.ForeachActivatedClient(Handle, activatedClientCallback).
338 ThrowIfError("Failed to get activated client.");
340 return clientIds.AsReadOnly();
344 /// Requests commands to the client.
347 /// The client can request the command to execute <see cref="Command"/>, <br/>
348 /// and then, the server receive the result of each request(command).
350 /// <param name="command">A <see cref="Command"/> class.</param>
351 /// <param name="clientId">The client Id to send command.</param>
352 /// <returns>A task that represents the asynchronous operation.</returns>
353 /// <exception cref="InvalidOperationException">
354 /// The server has already been stopped.<br/>
356 /// An internal error occurs.
358 /// <since_tizen> 5 </since_tizen>
359 public static async Task RequestAsync(Command command, string clientId)
361 command.SetRequestInformation(clientId);
363 var tcs = new TaskCompletionSource<MediaControllerError>();
364 string reqeustId = null;
366 EventHandler<CommandCompletedEventArgs> eventHandler = (s, e) =>
368 if (e.RequestId == reqeustId)
370 tcs.TrySetResult(e.Result);
376 CommandCompleted += eventHandler;
378 reqeustId = command.Request(Handle);
380 (await tcs.Task).ThrowIfError("Failed to request event.");
384 CommandCompleted -= eventHandler;
389 /// Sends the result of each command.
391 /// <param name="command">The command that return to client.</param>
392 /// <param name="result">The result of <paramref name="command"/>.</param>
393 /// <param name="bundle">The extra data.</param>
394 /// <exception cref="InvalidOperationException">
395 /// The server is not running .<br/>
397 /// An internal error occurs.
399 /// <since_tizen> 5 </since_tizen>
400 public static void Response(Command command, int result, Bundle bundle)
402 command.Response(Handle, result, bundle);
406 /// Sends the result of each command.
408 /// <param name="command">The command that return to client.</param>
409 /// <param name="result">The result of <paramref name="command"/>.</param>
410 /// <exception cref="InvalidOperationException">
411 /// The server is not running .<br/>
413 /// An internal error occurs.
415 /// <since_tizen> 5 </since_tizen>
416 public static void Response(Command command, int result)
418 command.Response(Handle, result, null);
423 /// Sets the content type of latest played media.
425 /// <param name="type">A value indicating the content type of the latest played media.</param>
426 /// <exception cref="InvalidOperationException">
427 /// The server is not running .<br/>
429 /// An internal error occurs.
431 /// <exception cref="ArgumentException"><paramref name="type"/> is invalid.</exception>
432 /// <since_tizen> 5 </since_tizen>
433 public static void SetPlaybackContentType(MediaControlContentType type)
435 ValidationUtil.ValidateEnum(typeof(MediaControlContentType), type, nameof(type));
437 Native.SetPlaybackContentType(Handle, type).ThrowIfError("Failed to set playback content type.");
441 /// Sets the path of icon.
443 /// <param name="path">The path of icon.</param>
444 /// <exception cref="InvalidOperationException">
445 /// The server is not running .<br/>
447 /// An internal error occurs.
449 /// <exception cref="ArgumentNullException"><paramref name="path"/> is invalid.</exception>
450 /// <since_tizen> 5 </since_tizen>
451 public static void SetIconPath(string path)
455 throw new ArgumentNullException(nameof(path));
458 Native.SetIconPath(Handle, path).ThrowIfError("Failed to set uri path.");
462 /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
464 /// <param name="capabilities">The set of <see cref="MediaControlPlaybackCommand"/> and <see cref="MediaControlCapabilitySupport"/>.</param>
465 /// <exception cref="InvalidOperationException">
466 /// The server is not running .<br/>
468 /// An internal error occurs.
470 /// <exception cref="ArgumentException"><paramref name="capabilities"/> is invalid.</exception>
471 /// <since_tizen> 5 </since_tizen>
472 public static void SetPlaybackCapability(Dictionary<MediaControlPlaybackCommand, MediaControlCapabilitySupport> capabilities)
474 foreach (var pair in capabilities)
476 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), pair.Key, nameof(pair.Key));
477 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), pair.Value, nameof(pair.Value));
479 SetPlaybackCapability(pair.Key, pair.Value);
480 Native.SetPlaybackCapability(Handle, pair.Key.ToNative(), pair.Value).
481 ThrowIfError("Failed to set playback capability.");
484 Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
488 /// Sets the capabilities by <see cref="MediaControlPlaybackCommand"/>.
490 /// <param name="action">A playback command.</param>
491 /// <param name="support">A value indicating whether the <paramref name="action"/> is supported or not.</param>
492 /// <exception cref="InvalidOperationException">
493 /// The server is not running .<br/>
495 /// An internal error occurs.
497 /// <exception cref="ArgumentException"><paramref name="action"/> or <paramref name="support"/> is invalid.</exception>
498 /// <since_tizen> 5 </since_tizen>
499 public static void SetPlaybackCapability(MediaControlPlaybackCommand action, MediaControlCapabilitySupport support)
501 ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackCommand), action, nameof(action));
502 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
504 Native.SetPlaybackCapability(Handle, action.ToNative(), support).ThrowIfError("Failed to set playback capability.");
506 Native.SaveAndNotifyPlaybackCapabilityUpdated(Handle).ThrowIfError("Failed to update playback capability.");
510 /// Sets the <see cref="MediaControlCapabilitySupport"/> indicating shuffle mode is supported or not.
512 /// <param name="support">A value indicating whether the shuffle mode is supported or not.</param>
513 /// <exception cref="InvalidOperationException">
514 /// The server is not running .<br/>
516 /// An internal error occurs.
518 /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
519 /// <since_tizen> 5 </since_tizen>
520 public static void SetShuffleModeCapability(MediaControlCapabilitySupport support)
522 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
524 Native.SetShuffleModeCapability(Handle, support).ThrowIfError("Failed to set shuffle mode capability.");
528 /// Sets the content type of latest played media.
530 /// <param name="support">A value indicating whether the <see cref="MediaControlRepeatMode"/> is supported or not.</param>
531 /// <exception cref="InvalidOperationException">
532 /// The server is not running .<br/>
534 /// An internal error occurs.
536 /// <exception cref="ArgumentException"><paramref name="support"/> is invalid.</exception>
537 /// <since_tizen> 5 </since_tizen>
538 public static void SetRepeatModeCapability(MediaControlCapabilitySupport support)
540 ValidationUtil.ValidateEnum(typeof(MediaControlCapabilitySupport), support, nameof(support));
542 Native.SetRepeatModeCapability(Handle, support).ThrowIfError("Failed to set shuffle mode capability.");
544 #endregion Capabilities