[MediaPlayer] Add API to export audio PCM data (#930)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.MediaPlayer / Player / Player.Events.cs
1 /*
2  * Copyright (c) 2016 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
17 using static Interop;
18 using System;
19 using System.ComponentModel;
20 using System.Diagnostics;
21
22 namespace Tizen.Multimedia
23 {
24     public partial class Player
25     {
26         /// <summary>
27         /// Occurs when the playback of a media is finished.
28         /// </summary>
29         /// <since_tizen> 3 </since_tizen>
30         public event EventHandler<EventArgs> PlaybackCompleted;
31         private NativePlayer.PlaybackCompletedCallback _playbackCompletedCallback;
32
33         /// <summary>
34         /// Occurs when the playback of a media is interrupted.
35         /// </summary>
36         /// <remarks>
37         /// If the reason is <see cref="PlaybackInterruptionReason.ResourceConflict"/>,
38         /// the player state will be one of <see cref="PlayerState.Idle"/>, <see cref="PlayerState.Ready"/>,
39         /// or <see cref="PlayerState.Paused"/>.
40         /// </remarks>
41         /// <seealso cref="Player.State"/>
42         /// <since_tizen> 3 </since_tizen>
43         public event EventHandler<PlaybackInterruptedEventArgs> PlaybackInterrupted;
44         private NativePlayer.PlaybackInterruptedCallback _playbackInterruptedCallback;
45
46         /// <summary>
47         /// Occurs when any error occurs.
48         /// </summary>
49         /// <remarks>The event handler will be executed on an internal thread.</remarks>
50         /// <since_tizen> 3 </since_tizen>
51         public event EventHandler<PlayerErrorOccurredEventArgs> ErrorOccurred;
52         private NativePlayer.PlaybackErrorCallback _playbackErrorCallback;
53
54         /// <summary>
55         /// Occurs when the video stream is changed.
56         /// </summary>
57         /// <remarks>The event handler will be executed on an internal thread.</remarks>
58         /// <since_tizen> 3 </since_tizen>
59         public event EventHandler<VideoStreamChangedEventArgs> VideoStreamChanged;
60         private NativePlayer.VideoStreamChangedCallback _videoStreamChangedCallback;
61
62         /// <summary>
63         /// Occurs when the subtitle is updated.
64         /// </summary>
65         /// <remarks>The event handler will be executed on an internal thread.</remarks>
66         /// <since_tizen> 3 </since_tizen>
67         public event EventHandler<SubtitleUpdatedEventArgs> SubtitleUpdated;
68         private NativePlayer.SubtitleUpdatedCallback _subtitleUpdatedCallback;
69
70         /// <summary>
71         /// Occurs when there is a change in the buffering status of streaming.
72         /// </summary>
73         /// <since_tizen> 3 </since_tizen>
74         public event EventHandler<BufferingProgressChangedEventArgs> BufferingProgressChanged;
75         private NativePlayer.BufferingProgressCallback _bufferingProgressCallback;
76
77         internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamAudioBufferStatusChanged;
78         private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamAudioBufferStatusChangedCallback;
79
80         internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamVideoBufferStatusChanged;
81         private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamVideoBufferStatusChangedCallback;
82
83         internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamAudioSeekingOccurred;
84         private NativePlayer.MediaStreamSeekCallback _mediaStreamAudioSeekCallback;
85
86         internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamVideoSeekingOccurred;
87         private NativePlayer.MediaStreamSeekCallback _mediaStreamVideoSeekCallback;
88
89         private void RegisterEvents()
90         {
91             RegisterSubtitleUpdatedCallback();
92             RegisterErrorOccurredCallback();
93             RegisterPlaybackInterruptedCallback();
94             RegisterVideoStreamChangedCallback();
95             RegisterBufferingCallback();
96             RegisterMediaStreamBufferStatusCallback();
97             RegisterMediaStreamSeekCallback();
98             RegisterPlaybackCompletedCallback();
99         }
100
101         private void RegisterSubtitleUpdatedCallback()
102         {
103             _subtitleUpdatedCallback = (duration, text, _) =>
104             {
105                 Log.Debug(PlayerLog.Tag, $"duration : {duration}, text : {text}");
106                 SubtitleUpdated?.Invoke(this, new SubtitleUpdatedEventArgs(duration, text));
107             };
108
109             NativePlayer.SetSubtitleUpdatedCb(Handle, _subtitleUpdatedCallback).
110                 ThrowIfFailed(this, "Failed to initialize the player");
111         }
112
113         private void RegisterPlaybackCompletedCallback()
114         {
115             _playbackCompletedCallback = _ =>
116             {
117                 Log.Debug(PlayerLog.Tag, "completed callback");
118                 PlaybackCompleted?.Invoke(this, EventArgs.Empty);
119             };
120             NativePlayer.SetCompletedCb(Handle, _playbackCompletedCallback).
121                 ThrowIfFailed(this, "Failed to set PlaybackCompleted");
122         }
123
124         private void RegisterPlaybackInterruptedCallback()
125         {
126             _playbackInterruptedCallback = (code, _) =>
127             {
128                 if (!Enum.IsDefined(typeof(PlaybackInterruptionReason), code))
129                 {
130                     return;
131                 }
132
133                 if (code == PlaybackInterruptionReason.ResourceConflict)
134                 {
135                     OnUnprepared();
136                 }
137
138                 Log.Warn(PlayerLog.Tag, $"interrupted reason : {code}");
139                 PlaybackInterrupted?.Invoke(this, new PlaybackInterruptedEventArgs(code));
140             };
141
142             NativePlayer.SetInterruptedCb(Handle, _playbackInterruptedCallback).
143                 ThrowIfFailed(this, "Failed to set PlaybackInterrupted");
144         }
145
146         private void RegisterErrorOccurredCallback()
147         {
148             _playbackErrorCallback = (code, _) =>
149             {
150                 //TODO handle service disconnected error.
151                 Log.Warn(PlayerLog.Tag, "error code : " + code);
152                 ErrorOccurred?.Invoke(this, new PlayerErrorOccurredEventArgs((PlayerError)code));
153             };
154
155             NativePlayer.SetErrorCb(Handle, _playbackErrorCallback).
156                 ThrowIfFailed(this, "Failed to set PlaybackError");
157         }
158
159         /// <summary>
160         /// Raises the <see cref="ErrorOccurred"/> event.
161         /// </summary>
162         /// <param name="e">
163         /// An <see cref="PlayerErrorOccurredEventArgs"/> that contains the event data.
164         /// </param>
165         [EditorBrowsable(EditorBrowsableState.Never)]
166         protected void OnErrorOccurred(PlayerErrorOccurredEventArgs e)
167         {
168             ErrorOccurred?.Invoke(this, e);
169         }
170
171         #region VideoFrameDecoded event
172         private EventHandler<VideoFrameDecodedEventArgs> _videoFrameDecoded;
173
174         private NativePlayer.VideoFrameDecodedCallback _videoFrameDecodedCallback;
175
176         /// <summary>
177         /// Occurs when a video frame is decoded.
178         /// </summary>
179         /// <remarks>
180         ///     <para>The event handler will be executed on an internal thread.</para>
181         ///     <para>The <see cref="VideoFrameDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
182         /// </remarks>
183         /// <feature>http://tizen.org/feature/multimedia.raw_video</feature>
184         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
185         /// <seealso cref="VideoFrameDecodedEventArgs.Packet"/>
186         /// <since_tizen> 3 </since_tizen>
187         public event EventHandler<VideoFrameDecodedEventArgs> VideoFrameDecoded
188         {
189             add
190             {
191                 ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
192
193                 _videoFrameDecoded += value;
194             }
195             remove
196             {
197                 ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
198
199                 _videoFrameDecoded -= value;
200             }
201         }
202
203         private void RegisterVideoFrameDecodedCallback()
204         {
205             _videoFrameDecodedCallback = (packetHandle, _) =>
206             {
207                 var handler = _videoFrameDecoded;
208                 if (handler != null)
209                 {
210                     Log.Debug(PlayerLog.Tag, "packet : " + packetHandle);
211                     handler.Invoke(this,
212                         new VideoFrameDecodedEventArgs(MediaPacket.From(packetHandle)));
213                 }
214                 else
215                 {
216                     MediaPacket.From(packetHandle).Dispose();
217                 }
218             };
219
220             NativePlayer.SetVideoFrameDecodedCb(Handle, _videoFrameDecodedCallback).
221                 ThrowIfFailed(this, "Failed to register the VideoFrameDecoded");
222         }
223         #endregion
224
225         #region AudioFrameDecoded event
226         /// <summary>
227         /// Occurs when a audio frame is decoded.
228         /// </summary>
229         /// <remarks>
230         ///     <para>The event handler will be executed on an internal thread.</para>
231         ///     <para>The <see cref="AudioDataDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
232         /// </remarks>
233         /// <seealso cref="AudioDataDecodedEventArgs.Packet"/>
234         /// <since_tizen> 6 </since_tizen>
235         public event EventHandler<AudioDataDecodedEventArgs> AudioDataDecoded;
236
237         private NativePlayer.AudioFrameDecodedCallback _audioFrameDecodedCallback;
238         #endregion
239
240         private void RegisterVideoStreamChangedCallback()
241         {
242             _videoStreamChangedCallback = (width, height, fps, bitrate, _) =>
243             {
244                 Log.Debug(PlayerLog.Tag, $"height={height}, width={width}, fps={fps}, bitrate={bitrate}");
245
246                 VideoStreamChanged?.Invoke(this, new VideoStreamChangedEventArgs(height, width, fps, bitrate));
247             };
248
249             NativePlayer.SetVideoStreamChangedCb(Handle, _videoStreamChangedCallback).
250                 ThrowIfFailed(this, "Failed to set the video stream changed callback");
251         }
252
253         private void RegisterBufferingCallback()
254         {
255             _bufferingProgressCallback = (percent, _) =>
256             {
257                 Log.Debug(PlayerLog.Tag, $"Buffering callback with percent { percent }");
258
259                 BufferingProgressChanged?.Invoke(this, new BufferingProgressChangedEventArgs(percent));
260             };
261
262             NativePlayer.SetBufferingCb(Handle, _bufferingProgressCallback).
263                 ThrowIfFailed(this, "Failed to set BufferingProgress");
264         }
265
266         private void RegisterMediaStreamBufferStatusCallback()
267         {
268             _mediaStreamAudioBufferStatusChangedCallback = (status, _) =>
269             {
270                 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
271                 Log.Debug(PlayerLog.Tag, "audio buffer status : " + status);
272
273                 MediaStreamAudioBufferStatusChanged?.Invoke(this,
274                     new MediaStreamBufferStatusChangedEventArgs(status));
275             };
276             _mediaStreamVideoBufferStatusChangedCallback = (status, _) =>
277             {
278                 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
279                 Log.Debug(PlayerLog.Tag, "video buffer status : " + status);
280
281                 MediaStreamVideoBufferStatusChanged?.Invoke(this,
282                     new MediaStreamBufferStatusChangedEventArgs(status));
283             };
284
285             RegisterMediaStreamBufferStatusCallback(StreamType.Audio, _mediaStreamAudioBufferStatusChangedCallback);
286             RegisterMediaStreamBufferStatusCallback(StreamType.Video, _mediaStreamVideoBufferStatusChangedCallback);
287         }
288
289         private void RegisterMediaStreamBufferStatusCallback(StreamType streamType,
290             NativePlayer.MediaStreamBufferStatusCallback cb)
291         {
292             NativePlayer.SetMediaStreamBufferStatusCb(Handle, streamType, cb).
293                 ThrowIfFailed(this, "Failed to SetMediaStreamBufferStatus");
294         }
295
296         private void RegisterMediaStreamSeekCallback()
297         {
298             _mediaStreamAudioSeekCallback = (offset, _) =>
299             {
300                 Log.Debug(PlayerLog.Tag, "audio seeking offset : " + offset);
301                 MediaStreamAudioSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
302             };
303             _mediaStreamVideoSeekCallback = (offset, _) =>
304             {
305                 Log.Debug(PlayerLog.Tag, "video seeking offset : " + offset);
306                 MediaStreamVideoSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
307             };
308
309             RegisterMediaStreamSeekCallback(StreamType.Audio, _mediaStreamAudioSeekCallback);
310             RegisterMediaStreamSeekCallback(StreamType.Video, _mediaStreamVideoSeekCallback);
311         }
312
313         private void RegisterMediaStreamSeekCallback(StreamType streamType, NativePlayer.MediaStreamSeekCallback cb)
314         {
315             NativePlayer.SetMediaStreamSeekCb(Handle, streamType, cb).
316                 ThrowIfFailed(this, "Failed to SetMediaStreamSeek");
317         }
318     }
319 }