[Multimedia] Fixed bugs.
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.MediaPlayer / Player / Player.Properties.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 using System;
17 using System.Threading.Tasks;
18 using System.Runtime.InteropServices;
19 using System.Diagnostics;
20 using System.IO;
21 using System.Threading;
22 using NativeDisplay = Interop.Display;
23 using static Interop;
24
25 namespace Tizen.Multimedia
26 {
27     /// <since_tizen> 3 </since_tizen>
28     public partial class Player
29     {
30         private void RetrieveProperties()
31         {
32             NativePlayer.GetAudioLatencyMode(Handle, out _audioLatencyMode).
33                 ThrowIfFailed("Failed to initialize the player");
34
35             NativePlayer.IsLooping(Handle, out _isLooping).ThrowIfFailed("Failed to initialize the player");
36         }
37
38         /// <summary>
39         /// Gets the native handle of the player.
40         /// </summary>
41         /// <value>An IntPtr that contains the native handle of the player.</value>
42         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
43         /// <since_tizen> 3 </since_tizen>
44         public IntPtr Handle
45         {
46             get
47             {
48                 ValidateNotDisposed();
49                 return _handle.DangerousGetHandle();
50             }
51         }
52
53         #region Network configuration
54         private string _cookie = "";
55         private string _userAgent = "";
56
57         /// <summary>
58         /// Gets or sets the cookie for streaming playback.
59         /// </summary>
60         /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
61         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
62         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
63         /// <exception cref="ArgumentNullException">The value to set is null.</exception>
64         /// <since_tizen> 3 </since_tizen>
65         public string Cookie
66         {
67             get
68             {
69                 Log.Info(PlayerLog.Tag, "get cookie : " + _cookie);
70                 return _cookie;
71             }
72             set
73             {
74                 ValidatePlayerState(PlayerState.Idle);
75
76                 if (value == null)
77                 {
78                     throw new ArgumentNullException(nameof(value), "Cookie can't be null.");
79                 }
80
81                 NativePlayer.SetStreamingCookie(Handle, value, value.Length).
82                     ThrowIfFailed("Failed to set the cookie to the player");
83
84                 _cookie = value;
85             }
86         }
87
88         /// <summary>
89         /// Gets or sets the user agent for streaming playback.
90         /// </summary>
91         /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
92         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
93         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
94         /// <exception cref="ArgumentNullException">The value to set is null.</exception>
95         /// <since_tizen> 3 </since_tizen>
96         public string UserAgent
97         {
98             get
99             {
100                 Log.Info(PlayerLog.Tag, "get useragent : " + _userAgent);
101                 return _userAgent;
102             }
103             set
104             {
105                 ValidatePlayerState(PlayerState.Idle);
106
107                 if (value == null)
108                 {
109                     throw new ArgumentNullException(nameof(value), "UserAgent can't be null.");
110                 }
111
112                 NativePlayer.SetStreamingUserAgent(Handle, value, value.Length).
113                     ThrowIfFailed("Failed to set the user agent to the player");
114
115                 _userAgent = value;
116             }
117         }
118         #endregion
119
120         /// <summary>
121         /// Gets the state of the player.
122         /// </summary>
123         /// <value>The current state of the player.</value>
124         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
125         /// <since_tizen> 3 </since_tizen>
126         public PlayerState State
127         {
128             get
129             {
130                 ValidateNotDisposed();
131
132                 if (IsPreparing())
133                 {
134                     return PlayerState.Preparing;
135                 }
136
137                 NativePlayer.GetState(Handle, out var state).ThrowIfFailed("Failed to retrieve the state of the player");
138
139                 Debug.Assert(Enum.IsDefined(typeof(PlayerState), state));
140
141                 return (PlayerState)state;
142             }
143         }
144
145         private AudioLatencyMode _audioLatencyMode;
146
147         /// <summary>
148         /// Gets or sets the audio latency mode.
149         /// </summary>
150         /// <value>A <see cref="AudioLatencyMode"/> that specifies the mode. The default is <see cref="AudioLatencyMode.Mid"/>.</value>
151         /// <remarks>
152         /// If the mode is <see cref="AudioLatencyMode.High"/>,
153         /// audio output interval can be increased, so it can keep more audio data to play.
154         /// But, state transition like pause or resume can be more slower than default(<see cref="AudioLatencyMode.Mid"/>).
155         /// </remarks>
156         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
157         /// <exception cref="ArgumentException">The value is not valid.</exception>
158         /// <since_tizen> 3 </since_tizen>
159         public AudioLatencyMode AudioLatencyMode
160         {
161             get
162             {
163                 Log.Info(PlayerLog.Tag, "get audio latency mode : " + _audioLatencyMode);
164                 return _audioLatencyMode;
165             }
166             set
167             {
168                 ValidateNotDisposed();
169
170                 if (_audioLatencyMode == value)
171                 {
172                     return;
173                 }
174                 ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value);
175
176                 NativePlayer.SetAudioLatencyMode(Handle, value).
177                     ThrowIfFailed("Failed to set the audio latency mode of the player");
178
179                 _audioLatencyMode = value;
180             }
181         }
182
183         private bool _isLooping;
184
185         /// <summary>
186         /// Gets or sets the looping state.
187         /// </summary>
188         /// <value>true if the playback is looping; otherwise, false. The default value is false.</value>
189         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
190         /// <since_tizen> 3 </since_tizen>
191         public bool IsLooping
192         {
193             get
194             {
195                 Log.Info(PlayerLog.Tag, "get looping : " + _isLooping);
196                 return _isLooping;
197             }
198             set
199             {
200                 ValidateNotDisposed();
201
202                 if (_isLooping == value)
203                 {
204                     return;
205                 }
206
207                 NativePlayer.SetLooping(Handle, value).ThrowIfFailed("Failed to set the looping state of the player");
208
209                 _isLooping = value;
210             }
211         }
212
213         #region Display methods
214         /// <summary>
215         /// Gets the display settings.
216         /// </summary>
217         /// <value>A <see cref="PlayerDisplaySettings"/> that specifies the display settings.</value>
218         /// <since_tizen> 3 </since_tizen>
219         public PlayerDisplaySettings DisplaySettings { get; }
220
221         private Display _display;
222
223         private PlayerErrorCode SetDisplay(Display display)
224         {
225             if (display == null)
226             {
227                 return NativeDisplay.SetDisplay(Handle, PlayerDisplayType.None, IntPtr.Zero);
228             }
229
230             return display.ApplyTo(this);
231         }
232
233         private void ReplaceDisplay(Display newDisplay)
234         {
235             _display?.SetOwner(null);
236             _display = newDisplay;
237             _display?.SetOwner(this);
238         }
239
240         /// <summary>
241         /// Gets or sets the display.
242         /// </summary>
243         /// <value>A <see cref="Multimedia.Display"/> that specifies the display.</value>
244         /// <remarks>The player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
245         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
246         /// <exception cref="ArgumentException">The value has already been assigned to another player.</exception>
247         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
248         /// <since_tizen> 3 </since_tizen>
249         public Display Display
250         {
251             get
252             {
253                 return _display;
254             }
255             set
256             {
257                 ValidatePlayerState(PlayerState.Idle);
258
259                 if (value?.Owner != null)
260                 {
261                     if (ReferenceEquals(this, value.Owner))
262                     {
263                         return;
264                     }
265
266                     throw new ArgumentException("The display has already been assigned to another.");
267                 }
268
269                 ReplaceDisplay(value);
270             }
271         }
272
273         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
274         {
275             Debug.Assert(IsDisposed == false);
276
277             Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
278             Debug.Assert(type != DisplayType.None);
279
280             return NativeDisplay.SetDisplay(Handle,
281                 type == DisplayType.Overlay ? PlayerDisplayType.Overlay : PlayerDisplayType.Evas, evasObject);
282         }
283
284         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEcoreWindow(IntPtr windowHandle)
285         {
286             Debug.Assert(IsDisposed == false);
287
288             return NativeDisplay.SetEcoreDisplay(Handle, PlayerDisplayType.Overlay, windowHandle);
289         }
290         #endregion
291
292         private PlayerTrackInfo _audioTrack;
293
294         /// <summary>
295         /// Gets the track info for the audio.
296         /// </summary>
297         /// <value>A <see cref="PlayerTrackInfo"/> for audio.</value>
298         /// <since_tizen> 3 </since_tizen>
299         public PlayerTrackInfo AudioTrackInfo
300         {
301             get
302             {
303                 if (_audioTrack == null)
304                 {
305                     _audioTrack = new PlayerTrackInfo(this, StreamType.Audio);
306                 }
307                 return _audioTrack;
308             }
309         }
310
311         private PlayerTrackInfo _subtitleTrackInfo;
312
313         /// <summary>
314         /// Gets the track info for the subtitle.
315         /// </summary>
316         /// <value>A <see cref="PlayerTrackInfo"/> for the subtitle.</value>
317         /// <since_tizen> 3 </since_tizen>
318         public PlayerTrackInfo SubtitleTrackInfo
319         {
320             get
321             {
322                 if (_subtitleTrackInfo == null)
323                 {
324                     _subtitleTrackInfo = new PlayerTrackInfo(this, StreamType.Text);
325                 }
326                 return _subtitleTrackInfo;
327             }
328         }
329
330         private StreamInfo _streamInfo;
331
332         /// <summary>
333         /// Gets the stream information.
334         /// </summary>
335         /// <value>A <see cref="StreamInfo"/> for this player.</value>
336         /// <since_tizen> 3 </since_tizen>
337         public StreamInfo StreamInfo
338         {
339             get
340             {
341                 if (_streamInfo == null)
342                 {
343                     _streamInfo = new StreamInfo(this);
344                 }
345                 return _streamInfo;
346             }
347         }
348
349         private readonly AudioEffect _audioEffect;
350
351         /// <summary>
352         /// Gets the audio effect.
353         /// </summary>
354         /// <feature>http://tizen.org/feature/multimedia.custom_audio_effect</feature>
355         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
356         /// <since_tizen> 3 </since_tizen>
357         public AudioEffect AudioEffect
358         {
359             get
360             {
361                 if (_audioEffect == null)
362                 {
363                     throw new NotSupportedException($"The feature({Features.AudioEffect}) is not supported.");
364                 }
365
366                 return _audioEffect;
367             }
368         }
369
370         /// <summary>
371         /// Gets or sets the mute state.
372         /// </summary>
373         /// <value>true if the player is muted; otherwise, false.</value>
374         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
375         /// <since_tizen> 3 </since_tizen>
376         public bool Muted
377         {
378             get
379             {
380                 bool value = false;
381                 NativePlayer.IsMuted(Handle, out value).ThrowIfFailed("Failed to get the mute state of the player");
382
383                 Log.Info(PlayerLog.Tag, "get mute : " + value);
384
385                 return value;
386             }
387             set
388             {
389                 NativePlayer.SetMute(Handle, value).ThrowIfFailed("Failed to set the mute state of the player");
390             }
391         }
392
393         /// <summary>
394         /// Gets or sets the current volume.
395         /// </summary>
396         /// <remarks>Valid volume range is from 0 to 1.0, inclusive.</remarks>
397         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
398         /// <exception cref="ArgumentOutOfRangeException">
399         ///     <paramref name="value"/> is less than zero.<br/>
400         ///     -or-<br/>
401         ///     <paramref name="value"/> is greater than 1.0.
402         /// </exception>
403         /// <since_tizen> 3 </since_tizen>
404         public float Volume
405         {
406             get
407             {
408                 float value = 0.0F;
409                 NativePlayer.GetVolume(Handle, out value, out value).
410                     ThrowIfFailed("Failed to get the volume of the player");
411                 return value;
412             }
413             set
414             {
415                 if (value < 0F || 1.0F < value)
416                 {
417                     throw new ArgumentOutOfRangeException(nameof(value), value,
418                         $"Valid volume range is 0 <= value <= 1.0, but got { value }.");
419                 }
420
421                 NativePlayer.SetVolume(Handle, value, value).
422                     ThrowIfFailed("Failed to set the volume of the player");
423             }
424         }
425     }
426 }