[MediaPlayer] fix descriptions (#955)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.MediaPlayer / Player / Player.cs
index ffb066b..ac1b78f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+using static Interop;
 using System;
-using System.Threading.Tasks;
-using System.Runtime.InteropServices;
+using System.ComponentModel;
 using System.Diagnostics;
 using System.IO;
+using System.Runtime.InteropServices;
 using System.Threading;
-using static Interop;
-using System.ComponentModel;
+using System.Threading.Tasks;
 
 namespace Tizen.Multimedia
 {
@@ -39,7 +40,7 @@ namespace Tizen.Multimedia
     /// </remarks>
     public partial class Player : IDisposable, IDisplayable<PlayerErrorCode>
     {
-        private PlayerHandle _handle;
+        private readonly PlayerHandle _handle;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Player"/> class.
@@ -47,23 +48,62 @@ namespace Tizen.Multimedia
         /// <since_tizen> 3 </since_tizen>
         public Player()
         {
-            NativePlayer.Create(out _handle).ThrowIfFailed("Failed to create player");
+            NativePlayer.Create(out _handle).ThrowIfFailed(null, "Failed to create player");
 
             Debug.Assert(_handle != null);
 
-            RetrieveProperties();
+            Initialize();
+        }
 
-            if (Features.IsSupported(Features.AudioEffect))
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Player"/> class with a native handle.
+        /// The class takes care of the life cycle of the handle.
+        /// Thus, it should not be closed/destroyed in another location.
+        /// </summary>
+        /// <param name="handle">The handle for the media player.</param>
+        /// <param name="errorHandler">The handle for occuring error.</param>
+        /// <remarks>
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected Player(IntPtr handle, Action<int, string> errorHandler)
+        {
+            // This constructor is to support TV product player.
+            // Be careful with 'handle'. It must be wrapped in safe handle, first.
+            _handle = handle != IntPtr.Zero ? new PlayerHandle(handle) :
+                throw new ArgumentException("Handle is invalid.", nameof(handle));
+
+            _errorHandler = errorHandler;
+        }
+
+        private bool _initialized;
+
+        /// <summary>
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected void Initialize()
+        {
+            if (_initialized)
+            {
+                throw new InvalidOperationException("It has already been initialized.");
+            }
+
+            if (Features.IsSupported(PlayerFeatures.AudioEffect))
             {
                 _audioEffect = new AudioEffect(this);
             }
 
-            if (Features.IsSupported(Features.RawVideo))
+            if (Features.IsSupported(PlayerFeatures.RawVideo))
             {
                 RegisterVideoFrameDecodedCallback();
             }
 
-            DisplaySettings = PlayerDisplaySettings.Create(this);
+            RegisterEvents();
+
+            _displaySettings = PlayerDisplaySettings.Create(this);
+
+            _initialized = true;
         }
 
         internal void ValidatePlayerState(params PlayerState[] desiredStates)
@@ -92,11 +132,24 @@ namespace Tizen.Multimedia
         public void Dispose()
         {
             Dispose(true);
+            GC.SuppressFinalize(this);
         }
 
-        private void Dispose(bool disposing)
+        /// <summary>
+        /// Releases the unmanaged resources used by the <see cref="Player"/>.
+        /// </summary>
+        /// <param name="disposing">
+        /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+        /// </param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void Dispose(bool disposing)
         {
-            if (!_disposed)
+            if (_disposed)
+            {
+                return;
+            }
+
+            if (disposing)
             {
                 ReplaceDisplay(null);
 
@@ -105,19 +158,19 @@ namespace Tizen.Multimedia
                     try
                     {
                         _source.DetachFrom(this);
+                        _source = null;
                     }
                     catch (Exception e)
                     {
                         Log.Error(PlayerLog.Tag, e.ToString());
                     }
                 }
-                _source = null;
 
                 if (_handle != null)
                 {
                     _handle.Dispose();
+                    _disposed = true;
                 }
-                _disposed = true;
             }
         }
 
@@ -139,7 +192,8 @@ namespace Tizen.Multimedia
         /// Gets the streaming download progress.
         /// </summary>
         /// <returns>The <see cref="DownloadProgress"/> containing current download progress.</returns>
-        /// <remarks>The player must be in the <see cref="PlayerState.Playing"/> or <see cref="PlayerState.Paused"/> state.</remarks>
+        /// <remarks>The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
+        /// or <see cref="PlayerState.Paused"/> state.</remarks>
         /// <exception cref="InvalidOperationException">
         ///     The player is not streaming.<br/>
         ///     -or-<br/>
@@ -149,14 +203,14 @@ namespace Tizen.Multimedia
         /// <since_tizen> 3 </since_tizen>
         public DownloadProgress GetDownloadProgress()
         {
-            ValidatePlayerState(PlayerState.Playing, PlayerState.Paused);
+            ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
 
             int start = 0;
             int current = 0;
             NativePlayer.GetStreamingDownloadProgress(Handle, out start, out current).
-                ThrowIfFailed("Failed to get download progress");
+                ThrowIfFailed(this, "Failed to get download progress");
 
-            Log.Info(PlayerLog.Tag, "get download progress : " + start + ", " + current);
+            Log.Info(PlayerLog.Tag, $"get download progress : {start}, {current}");
 
             return new DownloadProgress(start, current);
         }
@@ -164,6 +218,7 @@ namespace Tizen.Multimedia
         /// <summary>
         /// Sets the subtitle path for playback.
         /// </summary>
+        /// <param name="path">The absolute path of the subtitle file, it can be NULL in the <see cref="PlayerState.Idle"/> state.</param>
         /// <remarks>Only MicroDVD/SubViewer(*.sub), SAMI(*.smi), and SubRip(*.srt) subtitle formats are supported.
         ///     <para>The mediastorage privilege(http://tizen.org/privilege/mediastorage) must be added if any files are used to play located in the internal storage.
         ///     The externalstorage privilege(http://tizen.org/privilege/externalstorage) must be added if any files are used to play located in the external storage.</para>
@@ -193,7 +248,7 @@ namespace Tizen.Multimedia
             }
 
             NativePlayer.SetSubtitlePath(Handle, path).
-                ThrowIfFailed("Failed to set the subtitle path to the player");
+                ThrowIfFailed(this, "Failed to set the subtitle path to the player");
         }
 
         /// <summary>
@@ -208,7 +263,7 @@ namespace Tizen.Multimedia
             ValidatePlayerState(PlayerState.Idle);
 
             NativePlayer.SetSubtitlePath(Handle, null).
-                ThrowIfFailed("Failed to clear the subtitle of the player");
+                ThrowIfFailed(this, "Failed to clear the subtitle of the player");
         }
 
         /// <summary>
@@ -235,12 +290,12 @@ namespace Tizen.Multimedia
                 throw new InvalidOperationException("No subtitle set");
             }
 
-            err.ThrowIfFailed("Failed to the subtitle offset of the player");
+            err.ThrowIfFailed(this, "Failed to the subtitle offset of the player");
         }
 
         private void Prepare()
         {
-            NativePlayer.Prepare(Handle).ThrowIfFailed("Failed to prepare the player");
+            NativePlayer.Prepare(Handle).ThrowIfFailed(this, "Failed to prepare the player");
         }
 
         /// <summary>
@@ -249,7 +304,6 @@ namespace Tizen.Multimedia
         /// <since_tizen> 3 </since_tizen>
         protected virtual void OnPreparing()
         {
-            RegisterEvents();
         }
 
         /// <summary>
@@ -261,6 +315,7 @@ namespace Tizen.Multimedia
         /// <exception cref="InvalidOperationException">No source is set.</exception>
         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
+        /// <seealso cref="PlayerState.Preparing"/>
         /// <since_tizen> 3 </since_tizen>
         public virtual Task PrepareAsync()
         {
@@ -271,30 +326,92 @@ namespace Tizen.Multimedia
 
             ValidatePlayerState(PlayerState.Idle);
 
-            SetDisplay(_display).ThrowIfFailed("Failed to configure display of the player");
-
             OnPreparing();
 
-            var completionSource = new TaskCompletionSource<bool>();
-
             SetPreparing();
 
-            Task.Run(() =>
+            return Task.Factory.StartNew(() =>
             {
                 try
                 {
                     Prepare();
-                    ClearPreparing();
-                    completionSource.SetResult(true);
                 }
-                catch (Exception e)
+                finally
                 {
                     ClearPreparing();
-                    completionSource.TrySetException(e);
                 }
+            }, CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        /// <summary>
+        /// Prepares the cancellable media player for playback, asynchronously.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token to cancel preparing.</param>
+        /// <seealso cref="CancellationToken"/>
+        /// <returns>A task that represents the asynchronous prepare operation.</returns>
+        /// <remarks>To prepare the player, the player must be in the <see cref="PlayerState.Idle"/> state,
+        /// and a source must be set.
+        /// The state must be <see cref="PlayerState.Preparing"/> to cancel preparing.
+        /// When preparing is cancelled, a state will be changed to <see cref="PlayerState.Idle"/> from <see cref="PlayerState.Preparing"/>.</remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.
+        ///     -or-<br/>
+        ///     The player is not in the valid state.
+        ///     </exception>
+        /// <seealso cref="PrepareAsync()"/>
+        /// <seealso cref="Unprepare()"/>
+        /// <since_tizen> 6 </since_tizen>
+        public virtual async Task PrepareAsync(CancellationToken cancellationToken)
+        {
+            ValidateNotDisposed();
+
+            var taskCompletionSource = new TaskCompletionSource<bool>();
+
+            if (_source == null)
+            {
+                throw new InvalidOperationException("No source is set.");
+            }
+
+            ValidatePlayerState(PlayerState.Idle);
+
+            OnPreparing();
+
+            SetPreparing();
+
+            // register a callback to handle cancellation token anytime it occurs
+            cancellationToken.Register(() =>
+            {
+                ValidatePlayerState(PlayerState.Preparing);
+
+                // a user can get the state before finally block is called.
+                ClearPreparing();
+
+                Log.Warn(PlayerLog.Tag, $"preparing will be cancelled.");
+                NativePlayer.Unprepare(Handle).ThrowIfFailed(this, "Failed to unprepare the player");
+
+                taskCompletionSource.TrySetCanceled();
             });
 
-            return completionSource.Task;
+            _prepareCallback = _ =>
+            {
+                Log.Warn(PlayerLog.Tag, $"prepared callback is called.");
+                taskCompletionSource.TrySetResult(true);
+            };
+
+            try
+            {
+                NativePlayer.PrepareAsync(Handle, _prepareCallback, IntPtr.Zero).
+                    ThrowIfFailed(this, "Failed to prepare the player");
+
+                await taskCompletionSource.Task.ConfigureAwait(false);
+            }
+            finally
+            {
+                ClearPreparing();
+            }
         }
 
         /// <summary>
@@ -320,7 +437,7 @@ namespace Tizen.Multimedia
             }
             ValidatePlayerState(PlayerState.Ready, PlayerState.Paused, PlayerState.Playing);
 
-            NativePlayer.Unprepare(Handle).ThrowIfFailed("Failed to unprepare the player");
+            NativePlayer.Unprepare(Handle).ThrowIfFailed(this, "Failed to unprepare the player");
 
             OnUnprepared();
         }
@@ -340,10 +457,15 @@ namespace Tizen.Multimedia
         /// Starts or resumes playback.
         /// </summary>
         /// <remarks>
-        /// The player must be in the <see cref="PlayerState.Ready"/> or <see cref="PlayerState.Paused"/> state.
-        /// It has no effect if the player is already in the <see cref="PlayerState.Playing"/> state.<br/>
-        /// <br/>
-        /// Sound can be mixed with other sounds if you don't control the stream focus using <see cref="ApplyAudioStreamPolicy"/>.
+        /// Sound can be mixed with other sounds if you don't control the stream focus using <see cref="ApplyAudioStreamPolicy"/>.<br/>
+        ///      <para>Before Tizen 5.0, The player must be in the <see cref="PlayerState.Ready"/> or <see cref="PlayerState.Paused"/> state.
+        ///      It has no effect if the player is already in the <see cref="PlayerState.Playing"/> state.</para>
+        ///      <para>Since Tizen 5.0, The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
+        ///      or <see cref="PlayerState.Paused"/> state.<br/>
+        ///      In case of HTTP streaming playback, the player could be internally paused for buffering.
+        ///      If the application calls this function during the buffering, the playback will be resumed by force
+        ///      and the buffering message posting by <see cref="BufferingProgressChanged"/> will be stopped.<br/>
+        ///      In other cases, the player will keep playing without returning error.</para>
         /// </remarks>
         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
@@ -352,17 +474,13 @@ namespace Tizen.Multimedia
         /// <seealso cref="Pause"/>
         /// <seealso cref="PlaybackCompleted"/>
         /// <seealso cref="ApplyAudioStreamPolicy"/>
+        /// <seealso cref="BufferingProgressChanged"/>
         /// <since_tizen> 3 </since_tizen>
         public virtual void Start()
         {
-            if (State == PlayerState.Playing)
-            {
-                Log.Warn(PlayerLog.Tag, "playing state already");
-                return;
-            }
-            ValidatePlayerState(PlayerState.Ready, PlayerState.Paused);
+            ValidatePlayerState(PlayerState.Ready, PlayerState.Paused, PlayerState.Playing);
 
-            NativePlayer.Start(Handle).ThrowIfFailed("Failed to start the player");
+            NativePlayer.Start(Handle).ThrowIfFailed(this, "Failed to start the player");
         }
 
         /// <summary>
@@ -386,7 +504,7 @@ namespace Tizen.Multimedia
             }
             ValidatePlayerState(PlayerState.Paused, PlayerState.Playing);
 
-            NativePlayer.Stop(Handle).ThrowIfFailed("Failed to stop the player");
+            NativePlayer.Stop(Handle).ThrowIfFailed(this, "Failed to stop the player");
         }
 
         /// <summary>
@@ -410,12 +528,19 @@ namespace Tizen.Multimedia
 
             ValidatePlayerState(PlayerState.Playing);
 
-            NativePlayer.Pause(Handle).ThrowIfFailed("Failed to pause the player");
+            NativePlayer.Pause(Handle).ThrowIfFailed(this, "Failed to pause the player");
         }
 
         private MediaSource _source;
 
         /// <summary>
+        /// Determines whether MediaSource has set.
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected bool HasSource => _source != null;
+
+        /// <summary>
         /// Sets a media source for the player.
         /// </summary>
         /// <param name="source">A <see cref="MediaSource"/> that specifies the source for playback.</param>
@@ -457,7 +582,7 @@ namespace Tizen.Multimedia
         /// <since_tizen> 3 </since_tizen>
         public async Task<CapturedFrame> CaptureVideoAsync()
         {
-            ValidationUtil.ValidateFeatureSupported(Features.RawVideo);
+            ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
 
             ValidatePlayerState(PlayerState.Playing, PlayerState.Paused);
 
@@ -476,7 +601,7 @@ namespace Tizen.Multimedia
             using (var cbKeeper = ObjectKeeper.Get(cb))
             {
                 NativePlayer.CaptureVideo(Handle, cb)
-                    .ThrowIfFailed("Failed to capture the video");
+                    .ThrowIfFailed(this, "Failed to capture the video");
 
                 return await t.Task;
             }
@@ -485,11 +610,14 @@ namespace Tizen.Multimedia
         /// <summary>
         /// Gets the play position in milliseconds.
         /// </summary>
+        /// <returns>The current position in milliseconds.</returns>
         /// <remarks>The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
         /// or <see cref="PlayerState.Paused"/> state.</remarks>
         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
         /// <seealso cref="SetPlayPositionAsync(int, bool)"/>
+        /// <seealso cref="SetPlayPositionNanosecondsAsync(long, bool)"/>
+        /// <seealso cref="GetPlayPositionNanoseconds"/>
         /// <since_tizen> 3 </since_tizen>
         public int GetPlayPosition()
         {
@@ -498,29 +626,51 @@ namespace Tizen.Multimedia
             int playPosition = 0;
 
             NativePlayer.GetPlayPosition(Handle, out playPosition).
-                ThrowIfFailed("Failed to get the play position of the player");
+                ThrowIfFailed(this, "Failed to get the play position of the player");
 
-            Log.Info(PlayerLog.Tag, "get play position : " + playPosition);
+            Log.Info(PlayerLog.Tag, $"get play position : {playPosition}");
 
             return playPosition;
         }
 
-        private void SetPlayPosition(int milliseconds, bool accurate,
+        private void NativeSetPlayPosition(long position, bool accurate, bool nanoseconds,
             NativePlayer.SeekCompletedCallback cb)
         {
-            var ret = NativePlayer.SetPlayPosition(Handle, milliseconds, accurate, cb, IntPtr.Zero);
+            //Check if it is nanoseconds or milliseconds.
+            var ret = !nanoseconds ? NativePlayer.SetPlayPosition(Handle, (int)position, accurate, cb, IntPtr.Zero) :
+                NativePlayer.SetPlayPositionNanoseconds(Handle, position, accurate, cb, IntPtr.Zero);
 
             //Note that we assume invalid param error is returned only when the position value is invalid.
             if (ret == PlayerErrorCode.InvalidArgument)
             {
-                throw new ArgumentOutOfRangeException(nameof(milliseconds), milliseconds,
+                throw new ArgumentOutOfRangeException(nameof(position), position,
                     "The position is not valid.");
             }
             if (ret != PlayerErrorCode.None)
             {
                 Log.Error(PlayerLog.Tag, "Failed to set play position, " + (PlayerError)ret);
             }
-            ret.ThrowIfFailed("Failed to set play position");
+            ret.ThrowIfFailed(this, "Failed to set play position");
+        }
+
+        private async Task SetPlayPosition(long position, bool accurate, bool nanoseconds)
+        {
+            var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            bool immediateResult = _source is MediaStreamSource;
+
+            NativePlayer.SeekCompletedCallback cb = _ => taskCompletionSource.TrySetResult(true);
+
+            using (var cbKeeper = ObjectKeeper.Get(cb))
+            {
+                NativeSetPlayPosition(position, accurate, nanoseconds, immediateResult ? null : cb);
+
+                if (immediateResult)
+                {
+                    taskCompletionSource.TrySetResult(true);
+                }
+                await taskCompletionSource.Task;
+            }
         }
 
         /// <summary>
@@ -528,6 +678,7 @@ namespace Tizen.Multimedia
         /// </summary>
         /// <param name="position">The value indicating a desired position in milliseconds.</param>
         /// <param name="accurate">The value indicating whether the operation performs with accuracy.</param>
+        /// <returns>A task that represents the asynchronous operation.</returns>
         /// <remarks>
         ///     <para>The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
         ///     or <see cref="PlayerState.Paused"/> state.</para>
@@ -535,30 +686,71 @@ namespace Tizen.Multimedia
         ///     but this might be considerably slow. If false, the play position will be a nearest keyframe position.</para>
         ///     </remarks>
         /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
-        /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
+        /// <exception cref="InvalidOperationException">The player is not in the valid state.<br/>
+        ///     -or-<br/>
+        ///     In case of non-seekable content, the player will return error and keep playing without changing the play position.</exception>
         /// <exception cref="ArgumentOutOfRangeException">The specified position is not valid.</exception>
+        /// <seealso cref="SetPlayPositionNanosecondsAsync(long, bool)"/>
         /// <seealso cref="GetPlayPosition"/>
+        /// <seealso cref="GetPlayPositionNanoseconds"/>
         /// <since_tizen> 3 </since_tizen>
         public async Task SetPlayPositionAsync(int position, bool accurate)
         {
             ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
 
-            var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            await SetPlayPosition(position, accurate, false);
+        }
 
-            bool immediateResult = _source is MediaStreamSource;
+        /// <summary>
+        /// Gets the play position in nanoseconds.
+        /// </summary>
+        /// <returns>The current position in nanoseconds.</returns>
+        /// <remarks>The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
+        /// or <see cref="PlayerState.Paused"/> state.</remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
+        /// <seealso cref="SetPlayPositionAsync(int, bool)"/>
+        /// <seealso cref="SetPlayPositionNanosecondsAsync(long, bool)"/>
+        /// <seealso cref="GetPlayPosition"/>
+        /// <since_tizen> 5 </since_tizen>
+        public long GetPlayPositionNanoseconds()
+        {
+            ValidatePlayerState(PlayerState.Ready, PlayerState.Paused, PlayerState.Playing);
 
-            NativePlayer.SeekCompletedCallback cb = _ => taskCompletionSource.TrySetResult(true);
+            NativePlayer.GetPlayPositionNanoseconds(Handle, out long playPosition).
+                ThrowIfFailed(this, "Failed to get the play position(nsec) of the player");
 
-            using (var cbKeeper = ObjectKeeper.Get(cb))
-            {
-                SetPlayPosition(position, accurate, cb);
-                if (immediateResult)
-                {
-                    taskCompletionSource.TrySetResult(true);
-                }
+            Log.Info(PlayerLog.Tag, $"get play position(nsec) : {playPosition}");
 
-                await taskCompletionSource.Task;
-            }
+            return playPosition;
+        }
+
+        /// <summary>
+        /// Sets the seek position in nanoseconds for playback, asynchronously.
+        /// </summary>
+        /// <param name="position">The value indicating a desired position in nanoseconds.</param>
+        /// <param name="accurate">The value indicating whether the operation performs with accuracy.</param>
+        /// <returns>A task that represents the asynchronous operation.</returns>
+        /// <remarks>
+        ///     <para>The player must be in the <see cref="PlayerState.Ready"/>, <see cref="PlayerState.Playing"/>,
+        ///     or <see cref="PlayerState.Paused"/> state.</para>
+        ///     <para>If the <paramref name="accurate"/> is true, the play position will be adjusted as the specified <paramref name="position"/> value,
+        ///     but this might be considerably slow. If false, the play position will be a nearest keyframe position.</para>
+        ///     </remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">The player is not in the valid state.<br/>
+        ///     -or-<br/>
+        ///     In case of non-seekable content, the player will return error and keep playing without changing the play position.</exception>
+        /// <exception cref="ArgumentOutOfRangeException">The specified position is not valid.</exception>
+        /// <seealso cref="SetPlayPositionAsync(int, bool)"/>
+        /// <seealso cref="GetPlayPosition"/>
+        /// <seealso cref="GetPlayPositionNanoseconds"/>
+        /// <since_tizen> 5 </since_tizen>
+        public async Task SetPlayPositionNanosecondsAsync(long position, bool accurate)
+        {
+            ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
+
+            await SetPlayPosition(position, accurate, true);
         }
 
         /// <summary>
@@ -577,7 +769,7 @@ namespace Tizen.Multimedia
         ///     Streaming playback.
         /// </exception>
         /// <exception cref="ArgumentOutOfRangeException">
-        ///     <paramref name="rate"/> is less than 5.0.<br/>
+        ///     <paramref name="rate"/> is less than -5.0.<br/>
         ///     -or-<br/>
         ///     <paramref name="rate"/> is greater than 5.0.<br/>
         ///     -or-<br/>
@@ -593,7 +785,7 @@ namespace Tizen.Multimedia
 
             ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
 
-            NativePlayer.SetPlaybackRate(Handle, rate).ThrowIfFailed("Failed to set the playback rate.");
+            NativePlayer.SetPlaybackRate(Handle, rate).ThrowIfFailed(this, "Failed to set the playback rate.");
         }
 
         /// <summary>
@@ -617,12 +809,17 @@ namespace Tizen.Multimedia
         /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="policy"/> is null.</exception>
         /// <exception cref="NotSupportedException">
-        ///     <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported by <see cref="Player"/>.
+        ///     The required feature is not supported.<br/>
+        ///     -or-<br/>
+        ///     <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported on the current platform.
         /// </exception>
         /// <seealso cref="AudioStreamPolicy"/>
+        /// <feature>http://tizen.org/feature/multimedia.player.stream_info</feature>
         /// <since_tizen> 3 </since_tizen>
         public void ApplyAudioStreamPolicy(AudioStreamPolicy policy)
         {
+            ValidationUtil.ValidateFeatureSupported("http://tizen.org/feature/multimedia.player.stream_info");
+
             if (policy == null)
             {
                 throw new ArgumentNullException(nameof(policy));
@@ -630,8 +827,103 @@ namespace Tizen.Multimedia
 
             ValidatePlayerState(PlayerState.Idle);
 
-            NativePlayer.SetAudioPolicyInfo(Handle, policy.Handle).
-                ThrowIfFailed("Failed to set the audio stream policy to the player");
+            var ret = NativePlayer.SetAudioPolicyInfo(Handle, policy.Handle);
+
+            if (ret == PlayerErrorCode.InvalidArgument)
+            {
+                throw new NotSupportedException("The specified policy is not supported on the current system.");
+            }
+
+            ret.ThrowIfFailed(this, "Failed to set the audio stream policy to the player");
+        }
+
+        /// <summary>
+        /// Set the relative ROI (Region Of Interest) area as a decimal fraction based on the video source.
+        /// It can be regarded as zooming operation because the specified video area will be rendered to fit to the display.
+        /// </summary>
+        /// <param name="scaleRectangle">The containing the ROI area information.</param>
+        /// <remarks>
+        /// This function requires the ratio of the each coordinate and size to the video resolution size
+        /// to guarantee of showing the same area for the dynamic resolution video content.
+        /// This function have to be called after setting <see cref="Display"/>
+        /// </remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.
+        ///     -or-<br/>
+        ///     The <see cref="PlayerDisplayType"/> is not set to <see cref="PlayerDisplayType.Overlay"/>.
+        ///     </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///     <paramref name="scaleRectangle.ScaleX"/> is less than 0.0 or greater than 1.0.<br/>
+        ///     -or-<br/>
+        ///     <paramref name="scaleRectangle.ScaleY"/> is less than 0.0 or greater than 1.0.<br/>
+        ///     -or-<br/>
+        ///     <paramref name="scaleRectangle.ScaleWidth"/> is less than or equal to 0.0 or greater than 1.0.<br/>
+        ///     -or-<br/>
+        ///     <paramref name="scaleRectangle.ScaleHeight"/> is less than or equal to 0.0 or greater than 1.0.
+        /// </exception>
+        /// <seealso cref="ScaleRectangle"/>
+        /// <seealso cref="Display"/>
+        /// <seealso cref="StreamInfo.GetVideoProperties"/>
+        /// <seealso cref="GetVideoRoi"/>
+        /// <since_tizen> 5 </since_tizen>
+        public void SetVideoRoi(ScaleRectangle scaleRectangle)
+        {
+            ValidateNotDisposed();
+
+            if (scaleRectangle.ScaleX < 0 || scaleRectangle.ScaleX > 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(scaleRectangle.ScaleX), scaleRectangle.ScaleX, "Valid range is 0 to 1.0");
+            }
+            if (scaleRectangle.ScaleY < 0 || scaleRectangle.ScaleY > 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(scaleRectangle.ScaleY), scaleRectangle.ScaleY, "Valid range is 0 to 1.0");
+            }
+            if (scaleRectangle.ScaleWidth <= 0 || scaleRectangle.ScaleWidth > 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(scaleRectangle.ScaleWidth), scaleRectangle.ScaleWidth, "Valid range is 0 to 1.0 (except 0.0)");
+            }
+            if (scaleRectangle.ScaleHeight <= 0 || scaleRectangle.ScaleHeight > 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(scaleRectangle.ScaleHeight), scaleRectangle.ScaleHeight, "Valid range is 0 to 1.0 (except 0.0)");
+            }
+
+            NativePlayer.SetVideoRoi(Handle, scaleRectangle.ScaleX, scaleRectangle.ScaleY, scaleRectangle.ScaleWidth, scaleRectangle.ScaleHeight).ThrowIfFailed(this, "Failed to set the video roi area.");
+        }
+
+        /// <summary>
+        /// Get the relative ROI (Region Of Interest) area as a decimal fraction based on the video source.
+        /// </summary>
+        /// <returns>The <see cref="ScaleRectangle"/> containing the ROI area information.</returns>
+        /// <remarks>The specified ROI area is valid only in <see cref="PlayerDisplayType.Overlay"/>.</remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.
+        ///     </exception>
+        /// <seealso cref="Display"/>
+        /// <seealso cref="StreamInfo.GetVideoProperties"/>
+        /// <seealso cref="SetVideoRoi"/>
+        /// <since_tizen> 5 </since_tizen>
+        public ScaleRectangle GetVideoRoi()
+        {
+            ValidateNotDisposed();
+
+            NativePlayer.GetVideoRoi(Handle, out var scaleX, out var scaleY,
+                out var scaleWidth, out var scaleHeight).ThrowIfFailed(this, "Failed to get the video roi area");
+
+            return new ScaleRectangle(scaleX, scaleY, scaleWidth, scaleHeight);
+        }
+
+        /// <summary>
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected MediaPacket GetMediaPacket(IntPtr handle)
+        {
+            MediaPacket mediaPacket = handle != IntPtr.Zero ? MediaPacket.From(handle) :
+                throw new ArgumentException("MediaPacket handle is invalid.", nameof(handle));
+
+            return mediaPacket;
         }
         #endregion
 
@@ -644,24 +936,90 @@ namespace Tizen.Multimedia
             return Interlocked.CompareExchange(ref _isPreparing, 1, 1) == 1;
         }
 
-        private void SetPreparing()
+        /// <summary>
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected void SetPreparing()
         {
             Interlocked.Exchange(ref _isPreparing, 1);
         }
 
-        private void ClearPreparing()
+        /// <summary>
+        /// This supports the product infrastructure and is not intended to be used directly from application code.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected void ClearPreparing()
         {
             Interlocked.Exchange(ref _isPreparing, 0);
         }
-
         #endregion
 
         /// <summary>
-        /// This method supports the product infrastructure and is not intended to be used directly from application code.
+        /// Enable to decode an audio data for exporting PCM from a data.
         /// </summary>
-        /// <since_tizen> 4 </since_tizen>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected static Exception GetException(int errorCode, string message) =>
-            ((PlayerErrorCode)errorCode).GetException(message);
+        /// <param name="format">The media format handle required to audio PCM specification.
+        /// The format has to include <see cref="AudioMediaFormat.MimeType"/>,
+        /// <see cref="AudioMediaFormat.Channel"/> and <see cref="AudioMediaFormat.SampleRate"/>.
+        /// If the format is NULL, the original PCM format or platform default PCM format will be applied.</param>
+        /// <param name="option">The audio extract option.</param>
+        /// <remarks><para>The player must be in the <see cref="PlayerState.Idle"/> state.</para>
+        /// <para>A <see cref="AudioDataDecoded"/> event is called in a separate thread(not in the main loop).</para>
+        /// <para>The audio PCM data can be retrieved using a <see cref="AudioDataDecoded"/> event as a media packet
+        /// and it is available until it's destroyed by <see cref="MediaPacket.Dispose()"/>.
+        /// The packet has to be destroyed as quickly as possible after rendering the data
+        /// and all the packets have to be destroyed before <see cref="Unprepare"/> is called.</para></remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="ArgumentException">The value is not valid.</exception>
+        /// <exception cref="InvalidOperationException">
+        ///     Operation failed; internal error.
+        ///     -or-<br/>
+        ///     The player is not in the valid state.
+        ///     </exception>
+        /// <seealso cref="PlayerAudioExtractOption"/>
+        /// <seealso cref="DisableExportingAudioData"/>
+        /// <since_tizen> 6 </since_tizen>
+        public void EnableExportingAudioData(AudioMediaFormat format, PlayerAudioExtractOption option)
+        {
+            ValidatePlayerState(PlayerState.Idle);
+            ValidationUtil.ValidateEnum(typeof(PlayerAudioExtractOption), option, nameof(option));
+
+            _audioFrameDecodedCallback = (IntPtr packetHandle, IntPtr userData) =>
+            {
+                var handler = AudioDataDecoded;
+                if (handler != null)
+                {
+                    Log.Debug(PlayerLog.Tag, "packet : " + packetHandle.ToString());
+                    handler.Invoke(this,
+                        new AudioDataDecodedEventArgs(MediaPacket.From(packetHandle)));
+                }
+                else
+                {
+                    MediaPacket.From(packetHandle).Dispose();
+                }
+            };
+
+            NativePlayer.SetAudioFrameDecodedCb(Handle, format == null ? IntPtr.Zero : format.AsNativeHandle(), option,
+                _audioFrameDecodedCallback, IntPtr.Zero).ThrowIfFailed(this, "Failed to register the _audioFrameDecoded");
+        }
+
+        /// <summary>
+        /// Disable to decode an audio data.
+        /// </summary>
+        /// <remarks>The player must be in the <see cref="PlayerState.Idle"/> or <see cref="PlayerState.Ready"/>
+        /// state.</remarks>
+        /// <exception cref="ObjectDisposedException">The player has already been disposed of.</exception>
+        /// <exception cref="InvalidOperationException">The player is not in the valid state.</exception>
+        /// <seealso cref="EnableExportingAudioData"/>
+        /// <since_tizen> 6 </since_tizen>
+        public void DisableExportingAudioData()
+        {
+            ValidatePlayerState(PlayerState.Idle, PlayerState.Ready);
+
+            NativePlayer.UnsetAudioFrameDecodedCb(Handle).
+                ThrowIfFailed(this, "Failed to unset the AudioFrameDecoded");
+
+            _audioFrameDecodedCallback = null;
+        }
     }
 }