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