[MediaPlayer] Change descriptions of audio pitch APIs (#870)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.MediaPlayer / Player / Player.Properties.cs
1 /*
2  * Copyright (c) 2018 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     /// <summary>
28     /// Represents properties for streaming buffering time.
29     /// </summary>
30     /// <since_tizen> 5 </since_tizen>
31     public struct PlayerBufferingTime
32     {
33         /// <summary>
34         /// Initializes a new instance of the PlayerBufferingTime struct.
35         /// </summary>
36         /// <param name="preBufferMillisecond">A duration of buffering data that must be prerolled to start playback.</param>
37         /// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
38         /// 0 : use platform default value which could be different depending on the streaming type and network status. (the initial value)
39         /// -1 : use current value. (since 5.5)
40         /// <param name="reBufferMillisecond">A duration of buffering data that must be prerolled to resume playback,
41         /// when player is internally paused for buffering.
42         /// Except 0 and -1, setting at least 1000 milliseconds is recommended to ensure the normal buffering operation.
43         /// 0 : use platform default value, which depends on the streaming type and network status. It is set as the initial value of this parameter.
44         /// If the player state is <see cref="PlayerState.Playing"/> or <see cref="PlayerState.Paused"/>,
45         /// this function will return correct time value instead of 0. (since 5.5)
46         /// -1 : use current value. (since 5.5)</param>
47         /// <since_tizen> 5 </since_tizen>
48         public PlayerBufferingTime(int preBufferMillisecond = -1, int reBufferMillisecond = -1)
49         {
50             PreBufferMillisecond = preBufferMillisecond;
51             ReBufferMillisecond = reBufferMillisecond;
52         }
53
54         /// <summary>
55         /// Gets or sets the duration of buffering data that must be prerolled to start playback.
56         /// </summary>
57         /// <since_tizen> 5 </since_tizen>
58         public int PreBufferMillisecond
59         {
60             get;
61             set;
62         }
63
64         /// <summary>
65         /// Gets or sets the duration of buffering data that must be prerolled to resume playback
66         /// if player enters pause state for buffering.
67         /// </summary>
68         /// <since_tizen> 5 </since_tizen>
69         public int ReBufferMillisecond
70         {
71             get;
72             set;
73         }
74     }
75     /// <since_tizen> 3 </since_tizen>
76     public partial class Player
77     {
78         /// <summary>
79         /// Gets the native handle of the player.
80         /// </summary>
81         /// <value>An IntPtr that contains the native handle of the player.</value>
82         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
83         /// <since_tizen> 3 </since_tizen>
84         public IntPtr Handle
85         {
86             get
87             {
88                 ValidateNotDisposed();
89                 return _handle.DangerousGetHandle();
90             }
91         }
92
93         #region Network configuration
94         private string _cookie = "";
95         private string _userAgent = "";
96         private const int MinBufferingTime = -1;
97
98         /// <summary>
99         /// Gets or sets the cookie for streaming playback.
100         /// </summary>
101         /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
102         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
103         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
104         /// <exception cref="ArgumentNullException">The value to set is null.</exception>
105         /// <since_tizen> 3 </since_tizen>
106         public string Cookie
107         {
108             get
109             {
110                 return _cookie;
111             }
112             set
113             {
114                 ValidatePlayerState(PlayerState.Idle);
115
116                 if (value == null)
117                 {
118                     throw new ArgumentNullException(nameof(value), "Cookie can't be null.");
119                 }
120
121                 NativePlayer.SetStreamingCookie(Handle, value, value.Length).
122                     ThrowIfFailed(this, "Failed to set the cookie to the player");
123
124                 _cookie = value;
125             }
126         }
127
128         /// <summary>
129         /// Gets or sets the user agent for streaming playback.
130         /// </summary>
131         /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
132         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
133         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
134         /// <exception cref="ArgumentNullException">The value to set is null.</exception>
135         /// <since_tizen> 3 </since_tizen>
136         public string UserAgent
137         {
138             get
139             {
140                 return _userAgent;
141             }
142             set
143             {
144                 ValidatePlayerState(PlayerState.Idle);
145
146                 if (value == null)
147                 {
148                     throw new ArgumentNullException(nameof(value), "UserAgent can't be null.");
149                 }
150
151                 NativePlayer.SetStreamingUserAgent(Handle, value, value.Length).
152                     ThrowIfFailed(this, "Failed to set the user agent to the player");
153
154                 _userAgent = value;
155             }
156         }
157
158         /// <summary>
159         /// Gets or sets the streaming buffering time.
160         /// </summary>
161         /// <remarks>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
162         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
163         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
164         /// <exception cref="ArgumentOutOfRangeException">
165         ///     <pramref name="PreBufferMillisecond"/> is less than -1.<br/>
166         ///     -or-<br/>
167         ///     <pramref name="ReBufferMillisecond"/> is less than -1.<br/>
168         /// </exception>
169         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
170         /// <seealso cref="PlayerBufferingTime"/>
171         /// <since_tizen> 5 </since_tizen>
172         public PlayerBufferingTime BufferingTime
173         {
174             get
175             {
176                 ValidateNotDisposed();
177
178                 NativePlayer.GetStreamingBufferingTime(Handle, out var PreBuffMillisecond, out var ReBuffMillisecond).
179                         ThrowIfFailed(this, "Failed to get the buffering time of the player");
180
181                 return new PlayerBufferingTime(PreBuffMillisecond, ReBuffMillisecond);
182             }
183             set
184             {
185                 ValidatePlayerState(PlayerState.Idle);
186
187                 if (value.PreBufferMillisecond < MinBufferingTime || value.ReBufferMillisecond < MinBufferingTime)
188                 {
189                     throw new ArgumentOutOfRangeException(nameof(value), value,
190                         $"invalid range, got { value.PreBufferMillisecond }, { value.ReBufferMillisecond }.");
191                 }
192
193                 NativePlayer.SetStreamingBufferingTime(Handle, value.PreBufferMillisecond, value.ReBufferMillisecond).
194                     ThrowIfFailed(this, "Failed to set the buffering time of the player");
195             }
196         }
197         #endregion
198
199         /// <summary>
200         /// Gets the state of the player.
201         /// </summary>
202         /// <value>The current state of the player.</value>
203         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
204         /// <since_tizen> 3 </since_tizen>
205         public PlayerState State
206         {
207             get
208             {
209                 ValidateNotDisposed();
210
211                 if (IsPreparing())
212                 {
213                     return PlayerState.Preparing;
214                 }
215
216                 NativePlayer.GetState(Handle, out var state).
217                     ThrowIfFailed(this, "Failed to retrieve the state of the player");
218
219                 Debug.Assert(Enum.IsDefined(typeof(PlayerState), state));
220
221                 return (PlayerState)state;
222             }
223         }
224
225         /// <summary>
226         /// Gets or sets the audio latency mode.
227         /// </summary>
228         /// <value>A <see cref="AudioLatencyMode"/> that specifies the mode. The default is <see cref="AudioLatencyMode.Mid"/>.</value>
229         /// <remarks>
230         /// If the mode is <see cref="AudioLatencyMode.High"/>,
231         /// audio output interval can be increased, so it can keep more audio data to play.
232         /// But, state transition like pause or resume can be more slower than default(<see cref="AudioLatencyMode.Mid"/>).
233         /// </remarks>
234         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
235         /// <exception cref="ArgumentException">The value is not valid.</exception>
236         /// <since_tizen> 3 </since_tizen>
237         public AudioLatencyMode AudioLatencyMode
238         {
239             get
240             {
241                 NativePlayer.GetAudioLatencyMode(Handle, out var value).
242                     ThrowIfFailed(this, "Failed to get the audio latency mode of the player");
243
244                 return value;
245             }
246             set
247             {
248                 ValidateNotDisposed();
249
250                 ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value, nameof(value));
251
252                 NativePlayer.SetAudioLatencyMode(Handle, value).
253                     ThrowIfFailed(this, "Failed to set the audio latency mode of the player");
254             }
255         }
256
257         /// <summary>
258         /// Gets or sets the looping state.
259         /// </summary>
260         /// <value>true if the playback is looping; otherwise, false. The default value is false.</value>
261         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
262         /// <since_tizen> 3 </since_tizen>
263         public bool IsLooping
264         {
265             get
266             {
267                 NativePlayer.IsLooping(Handle, out var value).
268                     ThrowIfFailed(this, "Failed to get the looping state of the player");
269
270                 return value;
271             }
272             set
273             {
274                 ValidateNotDisposed();
275
276                 NativePlayer.SetLooping(Handle, value).
277                     ThrowIfFailed(this, "Failed to set the looping state of the player");
278             }
279         }
280
281         #region Display methods
282
283         private PlayerDisplaySettings _displaySettings;
284
285         /// <summary>
286         /// Gets the display settings.
287         /// </summary>
288         /// <value>A <see cref="PlayerDisplaySettings"/> that specifies the display settings.</value>
289         /// <since_tizen> 3 </since_tizen>
290         public PlayerDisplaySettings DisplaySettings => _displaySettings;
291
292         private Display _display;
293
294         private PlayerErrorCode SetDisplay(Display display)
295         {
296             if (display == null)
297             {
298                 return NativeDisplay.SetDisplay(Handle, PlayerDisplayType.None, IntPtr.Zero);
299             }
300
301             return display.ApplyTo(this);
302         }
303
304         private void ReplaceDisplay(Display newDisplay)
305         {
306             _display?.SetOwner(null);
307             _display = newDisplay;
308             _display?.SetOwner(this);
309         }
310
311         /// <summary>
312         /// Gets or sets the display.
313         /// </summary>
314         /// <value>A <see cref="Multimedia.Display"/> that specifies the display.</value>
315         /// <remarks>
316         ///     The player must be in the <see cref="PlayerState.Idle"/> state.<br/>
317         ///     The raw video feature(http://tizen.org/feature/multimedia.raw_video) is required if
318         ///     the display is created with <see cref="MediaView"/>.
319         /// </remarks>
320         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
321         /// <exception cref="ArgumentException">The value has already been assigned to another player.</exception>
322         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
323         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
324         /// <since_tizen> 3 </since_tizen>
325         public Display Display
326         {
327             get
328             {
329                 return _display;
330             }
331             set
332             {
333                 ValidatePlayerState(PlayerState.Idle);
334
335                 if (value != null && value.HasMediaView)
336                 {
337                     ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
338                 }
339
340                 if (value?.Owner != null)
341                 {
342                     if (ReferenceEquals(this, value.Owner))
343                     {
344                         return;
345                     }
346
347                     throw new ArgumentException("The display has already been assigned to another.");
348                 }
349
350                 SetDisplay(value).ThrowIfFailed(this, "Failed to configure display of the player");
351
352                 ReplaceDisplay(value);
353             }
354         }
355
356         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
357         {
358             Debug.Assert(IsDisposed == false);
359
360             Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
361             Debug.Assert(type != DisplayType.None);
362
363             return NativeDisplay.SetDisplay(Handle,
364                 type == DisplayType.Overlay ? PlayerDisplayType.Overlay : PlayerDisplayType.Evas, evasObject);
365         }
366
367         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEcoreWindow(IntPtr windowHandle)
368         {
369             Debug.Assert(IsDisposed == false);
370
371             return NativeDisplay.SetEcoreDisplay(Handle, PlayerDisplayType.Overlay, windowHandle);
372         }
373         #endregion
374
375         private PlayerTrackInfo _audioTrack;
376
377         /// <summary>
378         /// Gets the track info for the audio.
379         /// </summary>
380         /// <value>A <see cref="PlayerTrackInfo"/> for audio.</value>
381         /// <since_tizen> 3 </since_tizen>
382         public PlayerTrackInfo AudioTrackInfo
383         {
384             get
385             {
386                 if (_audioTrack == null)
387                 {
388                     _audioTrack = new PlayerTrackInfo(this, StreamType.Audio);
389                 }
390                 return _audioTrack;
391             }
392         }
393
394         private PlayerTrackInfo _subtitleTrackInfo;
395
396         /// <summary>
397         /// Gets the track info for the subtitle.
398         /// </summary>
399         /// <value>A <see cref="PlayerTrackInfo"/> for the subtitle.</value>
400         /// <since_tizen> 3 </since_tizen>
401         public PlayerTrackInfo SubtitleTrackInfo
402         {
403             get
404             {
405                 if (_subtitleTrackInfo == null)
406                 {
407                     _subtitleTrackInfo = new PlayerTrackInfo(this, StreamType.Text);
408                 }
409                 return _subtitleTrackInfo;
410             }
411         }
412
413         private StreamInfo _streamInfo;
414
415         /// <summary>
416         /// Gets the stream information.
417         /// </summary>
418         /// <value>A <see cref="StreamInfo"/> for this player.</value>
419         /// <since_tizen> 3 </since_tizen>
420         public StreamInfo StreamInfo
421         {
422             get
423             {
424                 if (_streamInfo == null)
425                 {
426                     _streamInfo = new StreamInfo(this);
427                 }
428                 return _streamInfo;
429             }
430         }
431
432         private AudioEffect _audioEffect;
433
434         /// <summary>
435         /// Gets the audio effect.
436         /// </summary>
437         /// <feature>http://tizen.org/feature/multimedia.custom_audio_effect</feature>
438         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
439         /// <since_tizen> 3 </since_tizen>
440         public AudioEffect AudioEffect
441         {
442             get
443             {
444                 if (_audioEffect == null)
445                 {
446                     throw new NotSupportedException($"The feature({PlayerFeatures.AudioEffect}) is not supported.");
447                 }
448
449                 return _audioEffect;
450             }
451         }
452
453         /// <summary>
454         /// Gets or sets the mute state.
455         /// </summary>
456         /// <value>true if the player is muted; otherwise, false.</value>
457         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
458         /// <since_tizen> 3 </since_tizen>
459         public bool Muted
460         {
461             get
462             {
463                 NativePlayer.IsMuted(Handle, out var value).
464                     ThrowIfFailed(this, "Failed to get the mute state of the player");
465
466                 Log.Info(PlayerLog.Tag, "get mute : " + value);
467
468                 return value;
469             }
470             set
471             {
472                 NativePlayer.SetMute(Handle, value).ThrowIfFailed(this, "Failed to set the mute state of the player");
473             }
474         }
475
476         /// <summary>
477         /// Gets or sets the current volume.
478         /// </summary>
479         /// <remarks>Valid volume range is from 0 to 1.0, inclusive.</remarks>
480         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
481         /// <exception cref="ArgumentOutOfRangeException">
482         ///     <paramref name="value"/> is less than zero.<br/>
483         ///     -or-<br/>
484         ///     <paramref name="value"/> is greater than 1.0.
485         /// </exception>
486         /// <since_tizen> 3 </since_tizen>
487         public float Volume
488         {
489             get
490             {
491                 float value = 0.0F;
492                 NativePlayer.GetVolume(Handle, out value, out value).
493                     ThrowIfFailed(this, "Failed to get the volume of the player");
494
495                 return value;
496             }
497             set
498             {
499                 if (value < 0F || 1.0F < value)
500                 {
501                     throw new ArgumentOutOfRangeException(nameof(value), value,
502                         $"Valid volume range is 0 <= value <= 1.0, but got { value }.");
503                 }
504
505                 NativePlayer.SetVolume(Handle, value, value).
506                     ThrowIfFailed(this, "Failed to set the volume of the player");
507             }
508         }
509
510         /// <summary>
511         /// Gets or sets the audio-only state.
512         /// </summary>
513         /// <value>true if the playback is audio-only mode; otherwise, false. The default value is false.</value>
514         /// The <see cref="Player"/> must be in the <see cref="PlayerState.Ready"/>,
515         /// <see cref="PlayerState.Playing"/>, or <see cref="PlayerState.Paused"/> state.
516         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
517         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
518         /// <since_tizen> 5 </since_tizen>
519         public bool IsAudioOnly
520         {
521             get
522             {
523                 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
524                 NativePlayer.IsAudioOnly(Handle, out var value).
525                     ThrowIfFailed(this, "Failed to get the audio-only state of the player");
526                 return value;
527             }
528             set
529             {
530                 ValidateNotDisposed();
531                 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
532                 NativePlayer.SetAudioOnly(Handle, value).
533                     ThrowIfFailed(this, "Failed to set the audio-only state of the player");
534             }
535         }
536
537         /// <summary>
538         /// Gets or sets the player's replaygain state.
539         /// </summary>
540         /// <value>If the replaygain status is true, replaygain is applied (if contents has a replaygain tag);
541         /// otherwise, the replaygain is not affected by tag and properties.</value>
542         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
543         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
544         /// <since_tizen> 5 </since_tizen>
545         public bool ReplayGain
546         {
547             get
548             {
549                 ValidateNotDisposed();
550                 NativePlayer.IsReplayGain(Handle, out var value).
551                     ThrowIfFailed(this, "Failed to get the replaygain of the player");
552                 return value;
553             }
554             set
555             {
556                 ValidateNotDisposed();
557                 NativePlayer.SetReplayGain(Handle, value).
558                     ThrowIfFailed(this, "Failed to set the replaygain of the player");
559             }
560         }
561
562         /// <summary>
563         /// Enables or disables controlling the pitch of audio.
564         /// Gets the status of controlling the pitch of audio.
565         /// </summary>
566         /// <value>The value indicating whether or not AudioPitch is enabled. The default is false.</value>
567         /// <remarks>This function is used for audio content only.
568         /// To set, the player must be in the <see cref="PlayerState.Idle"/> state.</remarks>
569         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
570         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
571         /// <seealso cref="AudioPitch"/>
572         /// <since_tizen> 6 </since_tizen>
573         public bool AudioPitchEnabled
574         {
575             get
576             {
577                 ValidateNotDisposed();
578                 NativePlayer.IsAudioPitchEnabled(Handle, out var value).
579                     ThrowIfFailed(this, "Failed to get whether the audio pitch is enabled or not");
580                 return value;
581             }
582
583             set
584             {
585                 ValidateNotDisposed();
586                 ValidatePlayerState(PlayerState.Idle);
587
588                 NativePlayer.SetAudioPitchEnabled(Handle, value).
589                     ThrowIfFailed(this, "Failed to enable the audio pitch of the player");
590             }
591         }
592
593         /// <summary>
594         /// Gets or sets the pitch of audio.
595         /// </summary>
596         /// <value>The audio stream pitch value. The default is 1.</value>
597         /// <remarks>Enabling pitch control could increase the CPU usage on some devices.
598         /// This function is used for audio content only.</remarks>
599         /// <exception cref="InvalidOperationException">A pitch is not enabled.</exception>
600         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
601         /// <exception cref="ArgumentOutOfRangeException">
602         ///     value is less than 0.5.
603         ///     -or-<br/>
604         ///     value is greater than 2.0.<br/>
605         /// </exception>
606         /// <seealso cref="AudioPitchEnabled"/>
607         /// <since_tizen> 6 </since_tizen>
608         public float AudioPitch
609         {
610             get
611             {
612                 ValidateNotDisposed();
613
614                 if (AudioPitchEnabled == false)
615                 {
616                     throw new InvalidOperationException("An audio pitch is not enabled.");
617                 }
618
619                 NativePlayer.GetAudioPitch(Handle, out var value).
620                     ThrowIfFailed(this, "Failed to get the audio pitch");
621
622                 return value;
623             }
624
625             set
626             {
627                 ValidateNotDisposed();
628
629                 if (AudioPitchEnabled == false)
630                 {
631                     throw new InvalidOperationException("An audio pitch is not enabled.");
632                 }
633
634                 if (value < 0.5F || 2.0F < value)
635                 {
636                     throw new ArgumentOutOfRangeException(nameof(value), value, "Valid value is 0.5 to 2.0");
637                 }
638
639                 NativePlayer.SetAudioPitch(Handle, value).ThrowIfFailed(this, "Failed to set the audio pitch");
640             }
641         }
642
643         private SphericalVideo _sphericalVideo;
644
645         /// <summary>
646         /// Gets the spherical video settings.
647         /// </summary>
648         /// <since_tizen> 5 </since_tizen>
649         public SphericalVideo SphericalVideo
650         {
651             get
652             {
653                 if (_sphericalVideo == null)
654                 {
655                     _sphericalVideo = new SphericalVideo(this);
656                 }
657
658                 return _sphericalVideo;
659             }
660         }
661
662         private AdaptiveVariants _adaptiveVariants;
663
664         /// <summary>
665         /// Gets the adaptive variants settings.
666         /// </summary>
667         /// <since_tizen> 5 </since_tizen>
668         public AdaptiveVariants AdaptiveVariants
669         {
670             get
671             {
672                 if (_adaptiveVariants == null)
673                 {
674                     _adaptiveVariants = new AdaptiveVariants(this);
675                 }
676
677                 return _adaptiveVariants;
678             }
679         }
680     }
681 }