[Multimedia] Fix rotation issue for portrait mode (#5105)
[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         /// <exception cref="NotAvailableException">
237         ///     If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
238         /// </exception>
239         /// <seealso cref="AudioOffload"/>
240         /// <since_tizen> 3 </since_tizen>
241         public AudioLatencyMode AudioLatencyMode
242         {
243             get
244             {
245                 AudioOffload.CheckDisabled();
246
247                 NativePlayer.GetAudioLatencyMode(Handle, out var value).
248                     ThrowIfFailed(this, "Failed to get the audio latency mode of the player");
249
250                 return value;
251             }
252             set
253             {
254                 ValidateNotDisposed();
255                 AudioOffload.CheckDisabled();
256
257                 ValidationUtil.ValidateEnum(typeof(AudioLatencyMode), value, nameof(value));
258
259                 NativePlayer.SetAudioLatencyMode(Handle, value).
260                     ThrowIfFailed(this, "Failed to set the audio latency mode of the player");
261             }
262         }
263
264         /// <summary>
265         /// Gets or sets the looping state.
266         /// </summary>
267         /// <value>true if the playback is looping; otherwise, false. The default value is false.</value>
268         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
269         /// <since_tizen> 3 </since_tizen>
270         public bool IsLooping
271         {
272             get
273             {
274                 NativePlayer.IsLooping(Handle, out var value).
275                     ThrowIfFailed(this, "Failed to get the looping state of the player");
276
277                 return value;
278             }
279             set
280             {
281                 ValidateNotDisposed();
282
283                 NativePlayer.SetLooping(Handle, value).
284                     ThrowIfFailed(this, "Failed to set the looping state of the player");
285             }
286         }
287
288         #region Display methods
289
290         private PlayerDisplaySettings _displaySettings;
291
292         /// <summary>
293         /// Gets the display settings.
294         /// </summary>
295         /// <value>A <see cref="PlayerDisplaySettings"/> that specifies the display settings.</value>
296         /// <since_tizen> 3 </since_tizen>
297         public PlayerDisplaySettings DisplaySettings => _displaySettings;
298
299         private Display _display;
300
301         private bool _uiSync;
302
303         private PlayerErrorCode SetDisplay(Display display)
304         {
305             if (display == null)
306             {
307                 return NativeDisplay.SetDisplay(Handle, PlayerDisplayType.None, IntPtr.Zero);
308             }
309
310             return display.ApplyTo(this);
311         }
312
313         private void ReplaceDisplay(Display newDisplay)
314         {
315             _display?.SetOwner(null);
316             _display = newDisplay;
317             _display?.SetOwner(this);
318         }
319
320         /// <summary>
321         /// Gets or sets the display.
322         /// </summary>
323         /// <value>A <see cref="Multimedia.Display"/> that specifies the display.</value>
324         /// <remarks>
325         ///     The player must be in the <see cref="PlayerState.Idle"/> state.<br/>
326         ///     The raw video feature(http://tizen.org/feature/multimedia.raw_video) is required if
327         ///     the display is created with <see cref="MediaView"/>.<br/>
328         ///     If a user wants to use video and UI sync mode, please use <see cref="Tizen.Multimedia.Display(NUI.Window, bool)"/>.(Since tizen 6.5)<br/>
329         ///     But <see cref="Tizen.Multimedia.Player.DisplaySettings"/> is not supported in UI sync mode.
330         /// </remarks>
331         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
332         /// <exception cref="ArgumentException">The value has already been assigned to another player.</exception>
333         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
334         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
335         /// <since_tizen> 3 </since_tizen>
336         public Display Display
337         {
338             get
339             {
340                 return _display;
341             }
342             set
343             {
344                 ValidatePlayerState(PlayerState.Idle);
345
346                 if (value != null && value.HasMediaView)
347                 {
348                     ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
349                 }
350
351                 if (value?.Owner != null)
352                 {
353                     if (ReferenceEquals(this, value.Owner))
354                     {
355                         return;
356                     }
357
358                     throw new ArgumentException("The display has already been assigned to another.");
359                 }
360
361                 _uiSync = value?.UiSync ?? false;
362
363                 SetDisplay(value).ThrowIfFailed(this, "Failed to configure display of the player");
364
365                 ReplaceDisplay(value);
366             }
367         }
368
369         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
370         {
371             Debug.Assert(IsDisposed == false);
372
373             Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
374             Debug.Assert(type != DisplayType.None);
375
376             return NativeDisplay.SetDisplay(Handle,
377                 type == DisplayType.Overlay ? PlayerDisplayType.Overlay : PlayerDisplayType.Evas, evasObject);
378         }
379
380         PlayerErrorCode IDisplayable<PlayerErrorCode>.ApplyEcoreWindow(IntPtr windowHandle, Rectangle rect, Rotation rotation)
381         {
382             Debug.Assert(IsDisposed == false);
383
384             return NativeDisplay.SetEcoreDisplay(Handle,
385                 _uiSync ? PlayerDisplayType.OverlayUISync : PlayerDisplayType.Overlay, windowHandle, rect.X, rect.Y,
386                 rotation == Rotation.Rotate0 || rotation == Rotation.Rotate180 ? rect.Height : rect.Width,
387                 rotation == Rotation.Rotate0 || rotation == Rotation.Rotate180 ? rect.Width : rect.Height);
388         }
389         #endregion
390
391         private PlayerTrackInfo _audioTrack;
392
393         /// <summary>
394         /// Gets the track info for the audio.
395         /// </summary>
396         /// <value>A <see cref="PlayerTrackInfo"/> for audio.</value>
397         /// <since_tizen> 3 </since_tizen>
398         public PlayerTrackInfo AudioTrackInfo
399         {
400             get
401             {
402                 if (_audioTrack == null)
403                 {
404                     _audioTrack = new PlayerTrackInfo(this, StreamType.Audio);
405                 }
406                 return _audioTrack;
407             }
408         }
409
410         private PlayerTrackInfo _subtitleTrackInfo;
411
412         /// <summary>
413         /// Gets the track info for the subtitle.
414         /// </summary>
415         /// <value>A <see cref="PlayerTrackInfo"/> for the subtitle.</value>
416         /// <since_tizen> 3 </since_tizen>
417         public PlayerTrackInfo SubtitleTrackInfo
418         {
419             get
420             {
421                 if (_subtitleTrackInfo == null)
422                 {
423                     _subtitleTrackInfo = new PlayerTrackInfo(this, StreamType.Text);
424                 }
425                 return _subtitleTrackInfo;
426             }
427         }
428
429         private StreamInfo _streamInfo;
430
431         /// <summary>
432         /// Gets the stream information.
433         /// </summary>
434         /// <value>A <see cref="StreamInfo"/> for this player.</value>
435         /// <since_tizen> 3 </since_tizen>
436         public StreamInfo StreamInfo
437         {
438             get
439             {
440                 if (_streamInfo == null)
441                 {
442                     _streamInfo = new StreamInfo(this);
443                 }
444                 return _streamInfo;
445             }
446         }
447
448         private AudioEffect _audioEffect;
449
450         /// <summary>
451         /// Gets the audio effect.
452         /// </summary>
453         /// <feature>http://tizen.org/feature/multimedia.custom_audio_effect</feature>
454         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
455         /// <since_tizen> 3 </since_tizen>
456         public AudioEffect AudioEffect
457         {
458             get
459             {
460                 if (_audioEffect == null)
461                 {
462                     throw new NotSupportedException($"The feature({PlayerFeatures.AudioEffect}) is not supported.");
463                 }
464
465                 return _audioEffect;
466             }
467         }
468
469         /// <summary>
470         /// Gets or sets the mute state.
471         /// </summary>
472         /// <value>true if the player is muted; otherwise, false.</value>
473         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
474         /// <since_tizen> 3 </since_tizen>
475         public bool Muted
476         {
477             get
478             {
479                 NativePlayer.IsMuted(Handle, out var value).
480                     ThrowIfFailed(this, "Failed to get the mute state of the player");
481
482                 Log.Info(PlayerLog.Tag, "get mute : " + value);
483
484                 return value;
485             }
486             set
487             {
488                 NativePlayer.SetMute(Handle, value).ThrowIfFailed(this, "Failed to set the mute state of the player");
489             }
490         }
491
492         /// <summary>
493         /// Gets or sets the current volume.
494         /// </summary>
495         /// <remarks>Valid volume range is from 0 to 1.0, inclusive.</remarks>
496         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
497         /// <exception cref="ArgumentOutOfRangeException">
498         ///     <paramref name="value"/> is less than zero.<br/>
499         ///     -or-<br/>
500         ///     <paramref name="value"/> is greater than 1.0.
501         /// </exception>
502         /// <since_tizen> 3 </since_tizen>
503         public float Volume
504         {
505             get
506             {
507                 float value = 0.0F;
508                 NativePlayer.GetVolume(Handle, out value, out value).
509                     ThrowIfFailed(this, "Failed to get the volume of the player");
510
511                 return value;
512             }
513             set
514             {
515                 if (value < 0F || 1.0F < value)
516                 {
517                     throw new ArgumentOutOfRangeException(nameof(value), value,
518                         $"Valid volume range is 0 <= value <= 1.0, but got { value }.");
519                 }
520
521                 NativePlayer.SetVolume(Handle, value, value).
522                     ThrowIfFailed(this, "Failed to set the volume of the player");
523             }
524         }
525
526         /// <summary>
527         /// Gets or sets the audio-only state.
528         /// </summary>
529         /// <value>true if the playback is audio-only mode; otherwise, false. The default value is false.</value>
530         /// The <see cref="Player"/> must be in the <see cref="PlayerState.Ready"/>,
531         /// <see cref="PlayerState.Playing"/>, or <see cref="PlayerState.Paused"/> state.
532         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
533         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
534         /// <since_tizen> 5 </since_tizen>
535         public bool IsAudioOnly
536         {
537             get
538             {
539                 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
540                 NativePlayer.IsAudioOnly(Handle, out var value).
541                     ThrowIfFailed(this, "Failed to get the audio-only state of the player");
542                 return value;
543             }
544             set
545             {
546                 ValidateNotDisposed();
547                 ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
548                 NativePlayer.SetAudioOnly(Handle, value).
549                     ThrowIfFailed(this, "Failed to set the audio-only state of the player");
550             }
551         }
552
553         /// <summary>
554         /// Gets or sets the player's replaygain state.
555         /// </summary>
556         /// <value>If the replaygain status is true, replaygain is applied (if contents has a replaygain tag);
557         /// otherwise, the replaygain is not affected by tag and properties.</value>
558         /// <remarks>This function could be unavailable depending on the audio codec type.</remarks>
559         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
560         /// <exception cref="InvalidOperationException">
561         ///     The player is not in the valid state.
562         /// </exception>
563         /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
564         ///     -or-<br/>
565         ///     The function is not available depending on the audio codec type. (Since tizen 6.0)
566         /// </exception>
567         /// <seealso cref="AudioOffload"/>
568         /// <seealso cref="AudioCodecType"/>
569         /// <since_tizen> 5 </since_tizen>
570         public bool ReplayGain
571         {
572             get
573             {
574                 ValidateNotDisposed();
575                 AudioOffload.CheckDisabled();
576
577                 NativePlayer.IsReplayGain(Handle, out var value).
578                     ThrowIfFailed(this, "Failed to get the replaygain of the player");
579                 return value;
580             }
581             set
582             {
583                 ValidateNotDisposed();
584                 AudioOffload.CheckDisabled();
585
586                 NativePlayer.SetReplayGain(Handle, value).
587                     ThrowIfFailed(this, "Failed to set the replaygain of the player");
588             }
589         }
590
591         /// <summary>
592         /// Enables or disables controlling the pitch of audio.
593         /// Gets the status of controlling the pitch of audio.
594         /// </summary>
595         /// <value>The value indicating whether or not AudioPitch is enabled. The default is false.</value>
596         /// <remarks>This function is used for audio content only.
597         /// To set, the player must be in the <see cref="PlayerState.Idle"/> state.
598         /// This function could be unavailable depending on the audio codec type.</remarks>
599         /// <exception cref="InvalidOperationException">
600         ///     The player is not in the valid state.
601         /// </exception>
602         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
603         /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
604         ///     -or-<br/>
605         ///     The function is not available depending on the audio codec type. (Since tizen 6.0)
606         /// </exception>
607         /// <seealso cref="AudioPitch"/>
608         /// <seealso cref="AudioOffload"/>
609         /// <seealso cref="AudioCodecType"/>
610         /// <since_tizen> 6 </since_tizen>
611         public bool AudioPitchEnabled
612         {
613             get
614             {
615                 ValidateNotDisposed();
616                 AudioOffload.CheckDisabled();
617
618                 NativePlayer.IsAudioPitchEnabled(Handle, out var value).
619                     ThrowIfFailed(this, "Failed to get whether the audio pitch is enabled or not");
620                 return value;
621             }
622
623             set
624             {
625                 ValidateNotDisposed();
626                 AudioOffload.CheckDisabled();
627                 ValidatePlayerState(PlayerState.Idle);
628
629                 NativePlayer.SetAudioPitchEnabled(Handle, value).
630                     ThrowIfFailed(this, "Failed to enable the audio pitch of the player");
631             }
632         }
633
634         /// <summary>
635         /// Gets or sets the pitch of audio.
636         /// </summary>
637         /// <value>The audio stream pitch value. The default is 1.</value>
638         /// <remarks>Enabling pitch control could increase the CPU usage on some devices.
639         /// This function is used for audio content only.
640         /// This function could be unavailable depending on the audio codec type.</remarks>
641         /// <exception cref="InvalidOperationException">
642         ///     A pitch is not enabled.
643         /// </exception>
644         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
645         /// <exception cref="ArgumentOutOfRangeException">
646         ///     value is less than 0.5.
647         ///     -or-<br/>
648         ///     value is greater than 2.0.
649         /// </exception>
650         /// <exception cref="NotAvailableException">If audio offload is enabled by calling <see cref="AudioOffload.IsEnabled"/>. (Since tizen 6.0)
651         ///     -or-<br/>
652         ///     The function is not available depending on the audio codec type. (Since tizen 6.0)
653         /// </exception>
654         /// <seealso cref="AudioPitchEnabled"/>
655         /// <seealso cref="AudioOffload"/>
656         /// <seealso cref="AudioCodecType"/>
657         /// <since_tizen> 6 </since_tizen>
658         public float AudioPitch
659         {
660             get
661             {
662                 ValidateNotDisposed();
663                 AudioOffload.CheckDisabled();
664
665                 if (AudioPitchEnabled == false)
666                 {
667                     throw new InvalidOperationException("An audio pitch is not enabled.");
668                 }
669
670                 NativePlayer.GetAudioPitch(Handle, out var value).
671                     ThrowIfFailed(this, "Failed to get the audio pitch");
672
673                 return value;
674             }
675
676             set
677             {
678                 ValidateNotDisposed();
679                 AudioOffload.CheckDisabled();
680
681                 if (AudioPitchEnabled == false)
682                 {
683                     throw new InvalidOperationException("An audio pitch is not enabled.");
684                 }
685
686                 if (value < 0.5F || 2.0F < value)
687                 {
688                     throw new ArgumentOutOfRangeException(nameof(value), value, "Valid value is 0.5 to 2.0");
689                 }
690
691                 NativePlayer.SetAudioPitch(Handle, value).ThrowIfFailed(this, "Failed to set the audio pitch");
692             }
693         }
694
695         /// <summary>
696         /// Gets or sets the default codec type of the audio decoder.
697         /// </summary>
698         /// <value>A <see cref="CodecType"/> specifies the type.
699         /// The default codec type could be different depending on the device capability.</value>
700         /// <remarks>
701         /// <para>To set, the player must be in the <see cref="PlayerState.Idle"/> state.</para>
702         /// <para>If H/W audio codec type is not supported in some cases, S/W audio codec type could be used instead.</para>
703         /// <para>The availability could be changed depending on the codec capability.
704         /// If an application wants to use the H/W audio codec type as default,
705         /// The following functions should be called after the codec type is set. :<br/>
706         /// <see cref="AudioEffect.IsAvailable"/><br/>
707         /// <see cref="EnableExportingAudioData"/><br/>
708         /// <see cref="DisableExportingAudioData"/><br/>
709         /// <see cref="ReplayGain"/><br/>
710         /// <see cref="AudioPitch"/><br/>
711         /// <see cref="AudioPitchEnabled"/><br/></para>
712         /// </remarks>
713         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
714         /// <exception cref="ArgumentException">The value is not valid.</exception>
715         /// <exception cref="InvalidOperationException">
716         ///     The player is not in the valid state.
717         ///     -or-<br/>
718         ///     Operation failed; internal error.
719         /// </exception>
720         /// <exception cref="CodecNotSupportedException">The selected codec is not supported.</exception>
721         /// <since_tizen> 6 </since_tizen>
722         public CodecType AudioCodecType
723         {
724             get
725             {
726                 ValidateNotDisposed();
727
728                 NativePlayer.GetAudioCodecType(Handle, out var value).
729                     ThrowIfFailed(this, "Failed to get the type of the audio codec");
730
731                 return value;
732             }
733             set
734             {
735                 ValidateNotDisposed();
736                 ValidatePlayerState(PlayerState.Idle);
737
738                 ValidationUtil.ValidateEnum(typeof(CodecType), value, nameof(value));
739
740                 NativePlayer.SetAudioCodecType(Handle, value).
741                     ThrowIfFailed(this, "Failed to set the type of the audio codec");
742             }
743         }
744
745         private SphericalVideo _sphericalVideo;
746
747         /// <summary>
748         /// Gets the spherical video settings.
749         /// </summary>
750         /// <since_tizen> 5 </since_tizen>
751         public SphericalVideo SphericalVideo
752         {
753             get
754             {
755                 if (_sphericalVideo == null)
756                 {
757                     _sphericalVideo = new SphericalVideo(this);
758                 }
759
760                 return _sphericalVideo;
761             }
762         }
763
764         private AdaptiveVariants _adaptiveVariants;
765
766         /// <summary>
767         /// Gets the adaptive variants settings.
768         /// </summary>
769         /// <since_tizen> 5 </since_tizen>
770         public AdaptiveVariants AdaptiveVariants
771         {
772             get
773             {
774                 if (_adaptiveVariants == null)
775                 {
776                     _adaptiveVariants = new AdaptiveVariants(this);
777                 }
778
779                 return _adaptiveVariants;
780             }
781         }
782
783         private AudioOffload _audioOffload;
784
785         /// <summary>
786         /// Gets the setting for audio offload.
787         /// </summary>
788         /// <since_tizen> 6 </since_tizen>
789         public AudioOffload AudioOffload
790         {
791             get
792             {
793                 if (_audioOffload == null)
794                 {
795                     _audioOffload = new AudioOffload(this);
796                 }
797
798                 return _audioOffload;
799             }
800         }
801     }
802 }