[MediaController] Add new APIs for sending command and its callback (#396)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Remoting / MediaController / MediaControlServer.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using Tizen.Applications;
20 using Native = Interop.MediaControllerServer;
21
22 namespace Tizen.Multimedia.Remoting
23 {
24     /// <summary>
25     /// Provides a means to set playback information and metadata and receive commands from clients.
26     /// </summary>
27     /// <seealso cref="MediaControllerManager"/>
28     /// <seealso cref="MediaController"/>
29     /// <since_tizen> 4 </since_tizen>
30     public static partial class MediaControlServer
31     {
32         private static IntPtr _handle = IntPtr.Zero;
33         private static bool? _isRunning;
34
35         /// <summary>
36         /// Gets a value indicating whether the server is running.
37         /// </summary>
38         /// <value>true if the server has started; otherwise, false.</value>
39         /// <seealso cref="Start"/>
40         /// <seealso cref="Stop"/>
41         /// <since_tizen> 4 </since_tizen>
42         public static bool IsRunning
43         {
44             get
45             {
46                 if (_isRunning.HasValue == false)
47                 {
48                     _isRunning = GetRunningState();
49                 }
50
51                 return _isRunning.Value;
52             }
53         }
54
55         private static bool GetRunningState()
56         {
57             IntPtr handle = IntPtr.Zero;
58             try
59             {
60                 Native.ConnectDb(out handle).ThrowIfError("Failed to retrieve the running state.");
61
62                 Native.CheckServerExist(handle, Applications.Application.Current.ApplicationInfo.ApplicationId,
63                     out var value).ThrowIfError("Failed to retrieve the running state.");
64
65                 return value;
66             }
67             finally
68             {
69                 if (handle != IntPtr.Zero)
70                 {
71                     Native.DisconnectDb(handle);
72                 }
73             }
74         }
75
76         private static void EnsureInitializedIfRunning()
77         {
78             if (_handle != IntPtr.Zero)
79             {
80                 return;
81             }
82
83             if (IsRunning == false)
84             {
85                 throw new InvalidOperationException("The server is not running.");
86             }
87
88             Initialize();
89         }
90
91         private static IntPtr Handle
92         {
93             get
94             {
95                 EnsureInitializedIfRunning();
96
97                 return _handle;
98             }
99         }
100
101         private static void Initialize()
102         {
103             Native.Create(out _handle).ThrowIfError("Failed to create media controller server.");
104
105             try
106             {
107                 RegisterPlaybackCommandReceivedEvent();
108                 RegisterPlaybackActionCommandReceivedEvent();
109                 RegisterPlaybackPositionCommandReceivedEvent();
110                 RegisterPlaylistCommandReceivedEvent();
111                 RegisterShuffleModeCommandReceivedEvent();
112                 RegisterRepeatModeCommandReceivedEvent();
113                 RegisterCustomCommandReceivedEvent();
114
115                 _isRunning = true;
116             }
117             catch
118             {
119                 Native.Destroy(_handle);
120                 _playbackCommandCallback = null;
121                 _handle = IntPtr.Zero;
122                 throw;
123             }
124         }
125
126         /// <summary>
127         /// Starts the media control server.
128         /// </summary>
129         /// <remarks>
130         /// When the server starts, <see cref="MediaControllerManager.ServerStarted"/> will be raised.
131         /// </remarks>
132         /// <privilege>http://tizen.org/privilege/mediacontroller.server</privilege>
133         /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
134         /// <exception cref="UnauthorizedAccessException">Caller does not have required privilege.</exception>
135         /// <seealso cref="MediaControllerManager.ServerStarted"/>
136         /// <since_tizen> 4 </since_tizen>
137         public static void Start()
138         {
139             Initialize();
140         }
141
142         /// <summary>
143         /// Stops the media control server.
144         /// </summary>
145         /// <remarks>
146         /// When the server stops, <see cref="MediaControllerManager.ServerStopped"/> will be raised.
147         /// </remarks>
148         /// <exception cref="InvalidOperationException">
149         ///     The server is not running .<br/>
150         ///     -or-<br/>
151         ///     An internal error occurs.
152         /// </exception>
153         /// <seealso cref="MediaControllerManager.ServerStopped"/>
154         /// <since_tizen> 4 </since_tizen>
155         public static void Stop()
156         {
157             EnsureInitializedIfRunning();
158
159             Native.Destroy(_handle).ThrowIfError("Failed to stop the server.");
160
161             _handle = IntPtr.Zero;
162             _playbackCommandCallback = null;
163             _isRunning = false;
164         }
165
166         /// <summary>
167         /// Updates playback state and playback position.</summary>
168         /// <param name="state">The playback state.</param>
169         /// <param name="position">The playback position in milliseconds.</param>
170         /// <exception cref="ArgumentException"><paramref name="state"/> is not valid.</exception>
171         /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero.</exception>
172         /// <exception cref="InvalidOperationException">
173         ///     The server is not running .<br/>
174         ///     -or-<br/>
175         ///     An internal error occurs.
176         /// </exception>
177         /// <since_tizen> 4 </since_tizen>
178         public static void SetPlaybackState(MediaControlPlaybackState state, long position)
179         {
180             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackState), state, nameof(state));
181
182             if (position < 0)
183             {
184                 throw new ArgumentOutOfRangeException(nameof(position), position, "position can't be less than zero.");
185             }
186
187             Native.SetPlaybackState(Handle, state.ToNative()).ThrowIfError("Failed to set playback state.");
188
189             Native.SetPlaybackPosition(Handle, (ulong)position).ThrowIfError("Failed to set playback position.");
190
191             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
192         }
193
194         private static void SetMetadata(MediaControllerNativeAttribute attribute, string value)
195         {
196             Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
197         }
198
199         /// <summary>
200         /// Updates metadata information.
201         /// </summary>
202         /// <param name="metadata">The metadata to update.</param>
203         /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception>
204         /// <exception cref="InvalidOperationException">
205         ///     The server is not running .<br/>
206         ///     -or-<br/>
207         ///     An internal error occurs.
208         /// </exception>
209         /// <since_tizen> 4 </since_tizen>
210         public static void SetMetadata(MediaControlMetadata metadata)
211         {
212             if (metadata == null)
213             {
214                 throw new ArgumentNullException(nameof(metadata));
215             }
216
217             SetMetadata(MediaControllerNativeAttribute.Title, metadata.Title);
218             SetMetadata(MediaControllerNativeAttribute.Artist, metadata.Artist);
219             SetMetadata(MediaControllerNativeAttribute.Album, metadata.Album);
220             SetMetadata(MediaControllerNativeAttribute.Author, metadata.Author);
221             SetMetadata(MediaControllerNativeAttribute.Genre, metadata.Genre);
222             SetMetadata(MediaControllerNativeAttribute.Duration, metadata.Duration);
223             SetMetadata(MediaControllerNativeAttribute.Date, metadata.Date);
224             SetMetadata(MediaControllerNativeAttribute.Copyright, metadata.Copyright);
225             SetMetadata(MediaControllerNativeAttribute.Description, metadata.Description);
226             SetMetadata(MediaControllerNativeAttribute.TrackNumber, metadata.TrackNumber);
227             SetMetadata(MediaControllerNativeAttribute.Picture, metadata.AlbumArtPath);
228
229             Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
230         }
231
232         /// <summary>
233         /// Updates the shuffle mode.
234         /// </summary>
235         /// <param name="enabled">A value indicating whether the shuffle mode is enabled.</param>
236         /// <exception cref="InvalidOperationException">
237         ///     The server is not running .<br/>
238         ///     -or-<br/>
239         ///     An internal error occurs.
240         /// </exception>
241         /// <since_tizen> 4 </since_tizen>
242         public static void SetShuffleModeEnabled(bool enabled)
243         {
244             Native.UpdateShuffleMode(Handle, enabled ? MediaControllerNativeShuffleMode.On : MediaControllerNativeShuffleMode.Off).
245                 ThrowIfError("Failed to set shuffle mode.");
246         }
247
248         /// <summary>
249         /// Updates the repeat mode.
250         /// </summary>
251         /// <param name="mode">A value indicating the repeat mode.</param>
252         /// <exception cref="InvalidOperationException">
253         ///     The server is not running .<br/>
254         ///     -or-<br/>
255         ///     An internal error occurs.
256         /// </exception>
257         /// <exception cref="ArgumentException"><paramref name="mode"/> is invalid.</exception>
258         /// <since_tizen> 4 </since_tizen>
259         public static void SetRepeatMode(MediaControlRepeatMode mode)
260         {
261             ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
262
263             Native.UpdateRepeatMode(Handle, mode.ToNative()).ThrowIfError("Failed to set repeat mode.");
264         }
265
266         /// <summary>
267         /// Sets the index of current playing media.
268         /// </summary>
269         /// <param name="index">The index of current playing media.</param>
270         /// <exception cref="ArgumentNullException"><paramref name="index"/> is null.</exception>
271         /// <exception cref="InvalidOperationException">
272         ///     The server is not running .<br/>
273         ///     -or-<br/>
274         ///     An internal error occurs.
275         /// </exception>
276         /// <since_tizen> 5 </since_tizen>
277         public static void SetIndexOfCurrentPlayingMedia(string index)
278         {
279             Native.SetIndexOfCurrentPlayingMedia(Handle, index)
280                 .ThrowIfError("Failed to set the index of current playing media");
281         }
282
283         /// <summary>
284         /// Delete playlist.
285         /// </summary>
286         /// <param name="playlist">The name of playlist.</param>
287         /// <exception cref="InvalidOperationException">
288         ///     The server is not running .<br/>
289         ///     -or-<br/>
290         ///     An internal error occurs.
291         /// </exception>
292         /// <since_tizen> 5 </since_tizen>
293         public static void RemovePlaylist(MediaControlPlaylist playlist)
294         {
295             Native.DeletePlaylist(Handle, playlist.Handle);
296             playlist.Dispose();
297         }
298
299         // Saves the playlist to the persistent storage.
300         internal static void SavePlaylist(IntPtr playlistHandle)
301         {
302             Native.SavePlaylist(Handle, playlistHandle).ThrowIfError("Failed to save playlist");
303         }
304
305         // Gets the playlist handle by name.
306         internal static IntPtr GetPlaylistHandle(string name)
307         {
308             Native.GetPlaylistHandle(Handle, name, out IntPtr playlistHandle)
309                 .ThrowIfError("Failed to get playlist handle by name");
310
311             return playlistHandle;
312         }
313
314         /// <summary>
315         /// Sends the result of each command.
316         /// </summary>
317         /// <param name="command">The command that return to client.</param>
318         /// <param name="result">The result of <paramref name="command"/>.</param>
319         /// <param name="bundle">The extra data.</param>
320         /// <exception cref="InvalidOperationException">
321         ///     The server is not running .<br/>
322         ///     -or-<br/>
323         ///     An internal error occurs.
324         /// </exception>
325         /// <since_tizen> 5 </since_tizen>
326         public static void Response(Command command, int result, Bundle bundle)
327         {
328             command.Response(Handle, result, bundle);
329         }
330
331         /// <summary>
332         /// Sends the result of each command.
333         /// </summary>
334         /// <param name="command">The command that return to client.</param>
335         /// <param name="result">The result of <paramref name="command"/>.</param>
336         /// <exception cref="InvalidOperationException">
337         ///     The server is not running .<br/>
338         ///     -or-<br/>
339         ///     An internal error occurs.
340         /// </exception>
341         /// <since_tizen> 5 </since_tizen>
342         public static void Response(Command command, int result)
343         {
344             command.Response(Handle, result, null);
345         }
346     }
347 }