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