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