[MediaPlayer] Add API to export audio PCM data (#930)
authornam <36914158+aferin@users.noreply.github.com>
Tue, 16 Jul 2019 07:58:24 +0000 (16:58 +0900)
committerGitHub <noreply@github.com>
Tue, 16 Jul 2019 07:58:24 +0000 (16:58 +0900)
* [MediaPlayer] Add API to export audio PCM data

src/Tizen.Multimedia.MediaPlayer/Interop/Interop.Player.cs
src/Tizen.Multimedia.MediaPlayer/Player/AudioDataDecodedEventArgs.cs [new file with mode: 0644]
src/Tizen.Multimedia.MediaPlayer/Player/Player.Events.cs
src/Tizen.Multimedia.MediaPlayer/Player/Player.cs
src/Tizen.Multimedia.MediaPlayer/Player/PlayerEnums.cs

index f40b77d..8c0cf7a 100644 (file)
@@ -37,6 +37,9 @@ internal static partial class Interop
         internal delegate void VideoFrameDecodedCallback(IntPtr packetHandle, IntPtr userData);
 
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+        internal delegate void AudioFrameDecodedCallback(IntPtr packetHandle, IntPtr userData);
+
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate void SubtitleUpdatedCallback(uint duration, string text, IntPtr userData);
 
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@@ -172,6 +175,13 @@ internal static partial class Interop
         [DllImport(Libraries.Player, EntryPoint = "player_unset_media_packet_video_frame_decoded_cb")]
         internal static extern PlayerErrorCode UnsetVideoFrameDecodedCb(IntPtr player);
 
+        [DllImport(Libraries.Player, EntryPoint = "player_set_media_packet_audio_frame_decoded_cb")]
+        internal static extern PlayerErrorCode SetAudioFrameDecodedCb(IntPtr player, IntPtr format, PlayerAudioExtractOption opt,
+            AudioFrameDecodedCallback callback, IntPtr userData = default(IntPtr));
+
+        [DllImport(Libraries.Player, EntryPoint = "player_unset_media_packet_audio_frame_decoded_cb")]
+        internal static extern PlayerErrorCode UnsetAudioFrameDecodedCb(IntPtr player);
+
         [DllImport(Libraries.Player, EntryPoint = "player_set_streaming_cookie")]
         internal static extern PlayerErrorCode SetStreamingCookie(IntPtr player, string cookie, int size);
 
diff --git a/src/Tizen.Multimedia.MediaPlayer/Player/AudioDataDecodedEventArgs.cs b/src/Tizen.Multimedia.MediaPlayer/Player/AudioDataDecodedEventArgs.cs
new file mode 100644 (file)
index 0000000..17a0085
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+
+namespace Tizen.Multimedia
+{
+    /// <summary>
+    /// Provides data for the <see cref="Player.AudioDataDecoded"/> event.
+    /// </summary>
+    /// <since_tizen> 6 </since_tizen>
+    public class AudioDataDecodedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Initializes a new instance of the AudioFrameDecodedEventArgs class.
+        /// </summary>
+        internal AudioDataDecodedEventArgs(MediaPacket packet)
+        {
+            Packet = packet;
+        }
+
+        /// <summary>
+        /// Gets the packet containing the decoded frame.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public MediaPacket Packet { get; }
+
+    }
+}
index 5d2f5f1..ed9f3dc 100644 (file)
@@ -169,7 +169,6 @@ namespace Tizen.Multimedia
         }
 
         #region VideoFrameDecoded event
-
         private EventHandler<VideoFrameDecodedEventArgs> _videoFrameDecoded;
 
         private NativePlayer.VideoFrameDecodedCallback _videoFrameDecodedCallback;
@@ -223,6 +222,21 @@ namespace Tizen.Multimedia
         }
         #endregion
 
+        #region AudioFrameDecoded event
+        /// <summary>
+        /// Occurs when a audio frame is decoded.
+        /// </summary>
+        /// <remarks>
+        ///     <para>The event handler will be executed on an internal thread.</para>
+        ///     <para>The <see cref="AudioDataDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
+        /// </remarks>
+        /// <seealso cref="AudioDataDecodedEventArgs.Packet"/>
+        /// <since_tizen> 6 </since_tizen>
+        public event EventHandler<AudioDataDecodedEventArgs> AudioDataDecoded;
+
+        private NativePlayer.AudioFrameDecodedCallback _audioFrameDecodedCallback;
+        #endregion
+
         private void RegisterVideoStreamChangedCallback()
         {
             _videoStreamChangedCallback = (width, height, fps, bitrate, _) =>
index 6040449..10f939a 100644 (file)
@@ -884,7 +884,77 @@ namespace Tizen.Multimedia
         {
             Interlocked.Exchange(ref _isPreparing, 0);
         }
-
         #endregion
+
+        /// <summary>
+        /// Enable to decode an audio data for exporting PCM from a data.
+        /// </summary>
+        /// <param name="format">The media format handle about required 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));
+
+            IntPtr formatHandle = IntPtr.Zero;
+
+            _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();
+                }
+            };
+
+            formatHandle = format.AsNativeHandle();
+
+            NativePlayer.SetAudioFrameDecodedCb(Handle, formatHandle, 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;
+        }
     }
 }
index 3a635ce..a611f18 100644 (file)
@@ -295,4 +295,32 @@ namespace Tizen.Multimedia
         /// </summary>
         Year
     }
+
+    /// <summary>
+    /// Enumeration of audio extract option.
+    /// </summary>
+    /// <seealso cref="Player.EnableExportingAudioData"/>
+    /// <since_tizen> 6 </since_tizen>
+    public enum PlayerAudioExtractOption
+    {
+        /// <summary>
+        /// Sync with the playback clock and multichannel audio stream
+        /// </summary>
+        Default = 0x00,
+
+        /// <summary>
+        /// No sync with the playback clock
+        /// </summary>
+        NoSyncWithClock = 0x01,
+
+        /// <summary>
+        /// Splits one interleaved multichannel audio stream into many mono audio streams
+        /// </summary>
+        Deinterleave = 0x02,
+
+        /// <summary>
+        /// No sync with clock and splits into mono streams
+        /// </summary>
+        NoSyncAndDeinterleave = 0x03,
+    }
 }