[MediaPlayer] add API about playback time to set/get in nonoseconds (#337)
authornam <36914158+kqjy777@users.noreply.github.com>
Fri, 27 Jul 2018 06:51:34 +0000 (15:51 +0900)
committerGitHub <noreply@github.com>
Fri, 27 Jul 2018 06:51:34 +0000 (15:51 +0900)
* [MediaPlayer] add API about playback time to set/get in nonoseconds

src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs
src/Tizen.Multimedia.MediaPlayer/Player/Player.ErrorHandler.cs
src/Tizen.Multimedia.MediaPlayer/Player/Player.cs
src/Tizen.Multimedia.MediaPlayer/Player/PlayerDisplaySettings.cs
src/Tizen.Multimedia.MediaPlayer/Player/PlayerTrackInfo.cs
src/Tizen.Multimedia.MediaPlayer/Player/StreamInfo.cs

index 60dfe6a..4655f85 100644 (file)
@@ -121,6 +121,13 @@ internal static partial class Interop
         internal static extern PlayerErrorCode SetPlayPosition(IntPtr player, int millisecond,
             bool accurate, SeekCompletedCallback cb, IntPtr userData = default(IntPtr));
 
+        [DllImport(Libraries.Player, EntryPoint = "player_get_play_position_nsec")]
+        internal static extern PlayerErrorCode GetPlayPositionNanoseconds(IntPtr player, out long nanoseconds);
+
+        [DllImport(Libraries.Player, EntryPoint = "player_set_play_position_nsec")]
+        internal static extern PlayerErrorCode SetPlayPositionNanoseconds(IntPtr player, long nanoseconds,
+            bool accurate, SeekCompletedCallback cb, IntPtr userData = default(IntPtr));
+
         [DllImport(Libraries.Player, EntryPoint = "player_set_mute")]
         internal static extern PlayerErrorCode SetMute(IntPtr player, bool muted);
 
@@ -243,6 +250,9 @@ internal static partial class Interop
         [DllImport(Libraries.Player, EntryPoint = "player_get_duration")]
         internal static extern PlayerErrorCode GetDuration(IntPtr player, out int duration);
 
+        [DllImport(Libraries.Player, EntryPoint = "player_get_duration_nsec")]
+        internal static extern PlayerErrorCode GetDurationNanoseconds(IntPtr player, out long duration);
+
         [DllImport(Libraries.Player, EntryPoint = "player_set_subtitle_path")]
         internal static extern PlayerErrorCode SetSubtitlePath(IntPtr player, string path);
 
index 30154ee..808a50d 100644 (file)
@@ -31,6 +31,8 @@ namespace Tizen.Multimedia
         /// <summary>
         /// This method supports the product infrastructure and is not intended to be used directly from application code.
         /// </summary>
+        /// <param name="errorCode">The error code according to the exception.</param>
+        /// <param name="message">The error message to show user.</param>
         /// <since_tizen> 4 </since_tizen>
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected static Exception GetException(int errorCode, string message) =>
index 43020b6..06c6165 100644 (file)
@@ -60,6 +60,8 @@ namespace Tizen.Multimedia
         /// 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>
@@ -209,6 +211,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>
@@ -529,11 +532,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()
         {
@@ -549,15 +555,17 @@ namespace Tizen.Multimedia
             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)
@@ -567,11 +575,32 @@ namespace Tizen.Multimedia
             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, cb);
+                if (immediateResult)
+                {
+                    taskCompletionSource.TrySetResult(true);
+                }
+
+                await taskCompletionSource.Task;
+            }
+        }
+
         /// <summary>
         /// Sets the seek position for playback, asynchronously.
         /// </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>
@@ -579,30 +608,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>
index 8de9bee..38b8a94 100644 (file)
@@ -30,6 +30,7 @@ namespace Tizen.Multimedia
         /// <summary>
         /// This constructor supports the product infrastructure and is not intended to be used directly from application code.
         /// </summary>
+        /// <param name="player"> The handle for the media player </param>
         /// <since_tizen> 4 </since_tizen>
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected PlayerDisplaySettings(Player player)
index f594b89..fa88af8 100644 (file)
@@ -65,6 +65,7 @@ namespace Tizen.Multimedia
         /// <summary>
         /// Gets the language code for the specified index, or null if the language is undefined.
         /// </summary>
+        /// <param name="index">The index of track.</param>
         /// <returns>The number of tracks.</returns>
         /// <remarks>
         ///     <para>The <see cref="Player"/> that owns this instance must be in the <see cref="PlayerState.Ready"/>,
index f1066b0..3f0519c 100644 (file)
@@ -260,7 +260,8 @@ namespace Tizen.Multimedia
         /// </exception>
         /// <exception cref="InvalidOperationException">
         /// The <see cref="Multimedia.Player"/> that this instance belongs to is not in the valid state.
-        /// </exception>
+        /// </exception>\
+        /// <seealso cref="GetDurationNanoseconds"/>
         /// <since_tizen> 3 </since_tizen>
         public int GetDuration()
         {
@@ -274,6 +275,33 @@ namespace Tizen.Multimedia
         }
 
         /// <summary>
+        /// Gets the duration in nanoseconds.
+        /// </summary>
+        /// <returns>The duration of the stream.</returns>
+        /// <remarks>
+        /// The <see cref="Multimedia.Player"/> that owns this instance must be in the <see cref="PlayerState.Ready"/>,
+        /// <see cref="PlayerState.Playing"/>, or <see cref="PlayerState.Paused"/> state.
+        /// </remarks>
+        /// <exception cref="ObjectDisposedException">
+        /// The <see cref="Multimedia.Player"/> that this instance belongs to has been disposed of.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        /// The <see cref="Multimedia.Player"/> that this instance belongs to is not in the valid state.
+        /// </exception>
+        /// <seealso cref="GetDuration"/>
+        /// <since_tizen> 5 </since_tizen>
+        public long GetDurationNanoseconds()
+        {
+            Player.ValidatePlayerState(PlayerState.Ready, PlayerState.Playing, PlayerState.Paused);
+
+            NativePlayer.GetDurationNanoseconds(Player.Handle, out var duration).
+                ThrowIfFailed(Player, "Failed to get the duration in nanoseconds");
+
+            Log.Info(PlayerLog.Tag, "get duration(nsec) : " + duration);
+            return duration;
+        }
+
+        /// <summary>
         /// Gets the properties of the audio.
         /// </summary>
         /// <returns>A <see cref="AudioStreamProperties"/> that contains the audio stream information.</returns>