Merge "[NUI] suuport NUIWatchApplication for watchface app"
[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 Native = Interop.MediaControllerServer;
19
20 namespace Tizen.Multimedia.Remoting
21 {
22     /// <summary>
23     /// Provides a means to set playback information and metadata and receive commands from clients.
24     /// </summary>
25     /// <seealso cref="MediaControllerManager"/>
26     /// <seealso cref="MediaController"/>
27     /// <since_tizen> 4 </since_tizen>
28     public static class MediaControlServer
29     {
30         private static IntPtr _handle = IntPtr.Zero;
31         private static bool? _isRunning;
32
33         /// <summary>
34         /// Gets a value indicating whether the server is running.
35         /// </summary>
36         /// <value>true if the server has started; otherwise, false.</value>
37         /// <seealso cref="Start"/>
38         /// <seealso cref="Stop"/>
39         /// <since_tizen> 4 </since_tizen>
40         public static bool IsRunning
41         {
42             get
43             {
44                 if (_isRunning.HasValue == false)
45                 {
46                     _isRunning = GetRunningState();
47                 }
48
49                 return _isRunning.Value;
50             }
51         }
52
53         private static bool GetRunningState()
54         {
55             IntPtr handle = IntPtr.Zero;
56             try
57             {
58                 Native.ConnectDb(out handle).ThrowIfError("Failed to retrieve the running state.");
59
60                 Native.CheckServerExist(handle, Applications.Application.Current.ApplicationInfo.ApplicationId,
61                     out var value).ThrowIfError("Failed to retrieve the running state.");
62
63                 return value;
64             }
65             finally
66             {
67                 if (handle != IntPtr.Zero)
68                 {
69                     Native.DisconnectDb(handle);
70                 }
71             }
72         }
73
74         private static void EnsureInitializedIfRunning()
75         {
76             if (_handle != IntPtr.Zero)
77             {
78                 return;
79             }
80
81             if (IsRunning == false)
82             {
83                 throw new InvalidOperationException("The server is not running.");
84             }
85
86             Initialize();
87         }
88
89         private static IntPtr Handle
90         {
91             get
92             {
93                 EnsureInitializedIfRunning();
94
95                 return _handle;
96             }
97         }
98
99         private static void Initialize()
100         {
101             Native.Create(out _handle).ThrowIfError("Failed to create media controller server.");
102
103             try
104             {
105                 RegisterPlaybackCommandReceivedEvent();
106                 _isRunning = true;
107             }
108             catch
109             {
110                 Native.Destroy(_handle);
111                 _playbackCommandCallback = null;
112                 _handle = IntPtr.Zero;
113                 throw;
114             }
115         }
116
117         /// <summary>
118         /// Starts the media control server.
119         /// </summary>
120         /// <remarks>
121         /// When the server starts, <see cref="MediaControllerManager.ServerStarted"/> will be raised.
122         /// </remarks>
123         /// <privilege>http://tizen.org/privilege/mediacontroller.server</privilege>
124         /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
125         /// <exception cref="UnauthorizedAccessException">Caller does not have required privilege.</exception>
126         /// <seealso cref="MediaControllerManager.ServerStarted"/>
127         /// <since_tizen> 4 </since_tizen>
128         public static void Start()
129         {
130             Initialize();
131         }
132
133         /// <summary>
134         /// Stops the media control server.
135         /// </summary>
136         /// <remarks>
137         /// When the server stops, <see cref="MediaControllerManager.ServerStopped"/> will be raised.
138         /// </remarks>
139         /// <exception cref="InvalidOperationException">
140         ///     The server is not running .<br/>
141         ///     -or-<br/>
142         ///     An internal error occurs.
143         /// </exception>
144         /// <seealso cref="MediaControllerManager.ServerStopped"/>
145         /// <since_tizen> 4 </since_tizen>
146         public static void Stop()
147         {
148             EnsureInitializedIfRunning();
149
150             Native.Destroy(_handle).ThrowIfError("Failed to stop the server.");
151
152             _handle = IntPtr.Zero;
153             _playbackCommandCallback = null;
154             _isRunning = false;
155         }
156
157         /// <summary>
158         /// Updates playback state and playback position.</summary>
159         /// <param name="state">The playback state.</param>
160         /// <param name="position">The playback position in milliseconds.</param>
161         /// <exception cref="ArgumentException"><paramref name="state"/> is not valid.</exception>
162         /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero.</exception>
163         /// <exception cref="InvalidOperationException">
164         ///     The server is not running .<br/>
165         ///     -or-<br/>
166         ///     An internal error occurs.
167         /// </exception>
168         /// <since_tizen> 4 </since_tizen>
169         public static void SetPlaybackState(MediaControlPlaybackState state, long position)
170         {
171             ValidationUtil.ValidateEnum(typeof(MediaControlPlaybackState), state, nameof(state));
172
173             if (position < 0)
174             {
175                 throw new ArgumentOutOfRangeException(nameof(position), position, "position can't be less than zero.");
176             }
177
178             Native.SetPlaybackState(Handle, state.ToCode()).ThrowIfError("Failed to set playback state.");
179
180             Native.SetPlaybackPosition(Handle, (ulong)position).ThrowIfError("Failed to set playback position.");
181
182             Native.UpdatePlayback(Handle).ThrowIfError("Failed to set playback.");
183         }
184
185         private static void SetMetadata(MediaControllerAttribute attribute, string value)
186         {
187             Native.SetMetadata(Handle, attribute, value).ThrowIfError($"Failed to set metadata({attribute}).");
188         }
189
190         /// <summary>
191         /// Updates metadata information.
192         /// </summary>
193         /// <param name="metadata">The metadata to update.</param>
194         /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception>
195         /// <exception cref="InvalidOperationException">
196         ///     The server is not running .<br/>
197         ///     -or-<br/>
198         ///     An internal error occurs.
199         /// </exception>
200         /// <since_tizen> 4 </since_tizen>
201         public static void SetMetadata(MediaControlMetadata metadata)
202         {
203             if (metadata == null)
204             {
205                 throw new ArgumentNullException(nameof(metadata));
206             }
207
208             SetMetadata(MediaControllerAttribute.Title, metadata.Title);
209             SetMetadata(MediaControllerAttribute.Artist, metadata.Artist);
210             SetMetadata(MediaControllerAttribute.Album, metadata.Album);
211             SetMetadata(MediaControllerAttribute.Author, metadata.Author);
212             SetMetadata(MediaControllerAttribute.Genre, metadata.Genre);
213             SetMetadata(MediaControllerAttribute.Duration, metadata.Duration);
214             SetMetadata(MediaControllerAttribute.Date, metadata.Date);
215             SetMetadata(MediaControllerAttribute.Copyright, metadata.Copyright);
216             SetMetadata(MediaControllerAttribute.Description, metadata.Description);
217             SetMetadata(MediaControllerAttribute.TrackNumber, metadata.TrackNumber);
218             SetMetadata(MediaControllerAttribute.Picture, metadata.AlbumArtPath);
219
220             Native.UpdateMetadata(Handle).ThrowIfError("Failed to set metadata.");
221         }
222
223         /// <summary>
224         /// Updates the shuffle mode.
225         /// </summary>
226         /// <param name="enabled">A value indicating whether the shuffle mode is enabled.</param>
227         /// <exception cref="InvalidOperationException">
228         ///     The server is not running .<br/>
229         ///     -or-<br/>
230         ///     An internal error occurs.
231         /// </exception>
232         /// <since_tizen> 4 </since_tizen>
233         public static void SetShuffleModeEnabled(bool enabled)
234         {
235             Native.UpdateShuffleMode(Handle, enabled ? MediaControllerShuffleMode.On : MediaControllerShuffleMode.Off).
236                 ThrowIfError("Failed to set shuffle mode.");
237         }
238
239         /// <summary>
240         /// Updates the repeat mode.
241         /// </summary>
242         /// <param name="mode">A value indicating the repeat mode.</param>
243         /// <exception cref="InvalidOperationException">
244         ///     The server is not running .<br/>
245         ///     -or-<br/>
246         ///     An internal error occurs.
247         /// </exception>
248         /// <exception cref="ArgumentException"><paramref name="mode"/> is invalid.</exception>
249         /// <since_tizen> 4 </since_tizen>
250         public static void SetRepeatMode(MediaControlRepeatMode mode)
251         {
252             ValidationUtil.ValidateEnum(typeof(MediaControlRepeatMode), mode, nameof(mode));
253
254             Native.UpdateRepeatMode(Handle, mode.ToNative()).ThrowIfError("Failed to set repeat mode.");
255         }
256
257         /// <summary>
258         /// Occurs when a client sends playback command.
259         /// </summary>
260         /// <since_tizen> 4 </since_tizen>
261         public static event EventHandler<PlaybackCommandReceivedEventArgs> PlaybackCommandReceived;
262
263         private static Native.PlaybackStateCommandReceivedCallback _playbackCommandCallback;
264
265         private static void RegisterPlaybackCommandReceivedEvent()
266         {
267             _playbackCommandCallback = (clientName, playbackCode, _) =>
268             {
269                 PlaybackCommandReceived?.Invoke(null, new PlaybackCommandReceivedEventArgs(clientName, playbackCode.ToCommand()));
270             };
271             Native.SetPlaybackStateCmdRecvCb(Handle, _playbackCommandCallback).
272                 ThrowIfError("Failed to init PlaybackStateCommandReceived event."); ;
273         }
274     }
275 }