[MediaPlayer] Add API to be able to cancel preparing it (#944)
[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         private NativePlayer.PrepareCallback _prepareCallback;
78
79         internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamAudioBufferStatusChanged;
80         private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamAudioBufferStatusChangedCallback;
81
82         internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamVideoBufferStatusChanged;
83         private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamVideoBufferStatusChangedCallback;
84
85         internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamAudioSeekingOccurred;
86         private NativePlayer.MediaStreamSeekCallback _mediaStreamAudioSeekCallback;
87
88         internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamVideoSeekingOccurred;
89         private NativePlayer.MediaStreamSeekCallback _mediaStreamVideoSeekCallback;
90
91         private void RegisterEvents()
92         {
93             RegisterSubtitleUpdatedCallback();
94             RegisterErrorOccurredCallback();
95             RegisterPlaybackInterruptedCallback();
96             RegisterVideoStreamChangedCallback();
97             RegisterBufferingCallback();
98             RegisterMediaStreamBufferStatusCallback();
99             RegisterMediaStreamSeekCallback();
100             RegisterPlaybackCompletedCallback();
101         }
102
103         private void RegisterSubtitleUpdatedCallback()
104         {
105             _subtitleUpdatedCallback = (duration, text, _) =>
106             {
107                 Log.Debug(PlayerLog.Tag, $"duration : {duration}, text : {text}");
108                 SubtitleUpdated?.Invoke(this, new SubtitleUpdatedEventArgs(duration, text));
109             };
110
111             NativePlayer.SetSubtitleUpdatedCb(Handle, _subtitleUpdatedCallback).
112                 ThrowIfFailed(this, "Failed to initialize the player");
113         }
114
115         private void RegisterPlaybackCompletedCallback()
116         {
117             _playbackCompletedCallback = _ =>
118             {
119                 Log.Debug(PlayerLog.Tag, "completed callback");
120                 PlaybackCompleted?.Invoke(this, EventArgs.Empty);
121             };
122             NativePlayer.SetCompletedCb(Handle, _playbackCompletedCallback).
123                 ThrowIfFailed(this, "Failed to set PlaybackCompleted");
124         }
125
126         private void RegisterPlaybackInterruptedCallback()
127         {
128             _playbackInterruptedCallback = (code, _) =>
129             {
130                 if (!Enum.IsDefined(typeof(PlaybackInterruptionReason), code))
131                 {
132                     return;
133                 }
134
135                 if (code == PlaybackInterruptionReason.ResourceConflict)
136                 {
137                     OnUnprepared();
138                 }
139
140                 Log.Warn(PlayerLog.Tag, $"interrupted reason : {code}");
141                 PlaybackInterrupted?.Invoke(this, new PlaybackInterruptedEventArgs(code));
142             };
143
144             NativePlayer.SetInterruptedCb(Handle, _playbackInterruptedCallback).
145                 ThrowIfFailed(this, "Failed to set PlaybackInterrupted");
146         }
147
148         private void RegisterErrorOccurredCallback()
149         {
150             _playbackErrorCallback = (code, _) =>
151             {
152                 //TODO handle service disconnected error.
153                 Log.Warn(PlayerLog.Tag, "error code : " + code);
154                 ErrorOccurred?.Invoke(this, new PlayerErrorOccurredEventArgs((PlayerError)code));
155             };
156
157             NativePlayer.SetErrorCb(Handle, _playbackErrorCallback).
158                 ThrowIfFailed(this, "Failed to set PlaybackError");
159         }
160
161         /// <summary>
162         /// Raises the <see cref="ErrorOccurred"/> event.
163         /// </summary>
164         /// <param name="e">
165         /// An <see cref="PlayerErrorOccurredEventArgs"/> that contains the event data.
166         /// </param>
167         [EditorBrowsable(EditorBrowsableState.Never)]
168         protected void OnErrorOccurred(PlayerErrorOccurredEventArgs e)
169         {
170             ErrorOccurred?.Invoke(this, e);
171         }
172
173         #region VideoFrameDecoded event
174         private EventHandler<VideoFrameDecodedEventArgs> _videoFrameDecoded;
175
176         private NativePlayer.VideoFrameDecodedCallback _videoFrameDecodedCallback;
177
178         /// <summary>
179         /// Occurs when a video frame is decoded.
180         /// </summary>
181         /// <remarks>
182         ///     <para>The event handler will be executed on an internal thread.</para>
183         ///     <para>The <see cref="VideoFrameDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
184         /// </remarks>
185         /// <feature>http://tizen.org/feature/multimedia.raw_video</feature>
186         /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
187         /// <seealso cref="VideoFrameDecodedEventArgs.Packet"/>
188         /// <since_tizen> 3 </since_tizen>
189         public event EventHandler<VideoFrameDecodedEventArgs> VideoFrameDecoded
190         {
191             add
192             {
193                 ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
194
195                 _videoFrameDecoded += value;
196             }
197             remove
198             {
199                 ValidationUtil.ValidateFeatureSupported(PlayerFeatures.RawVideo);
200
201                 _videoFrameDecoded -= value;
202             }
203         }
204
205         private void RegisterVideoFrameDecodedCallback()
206         {
207             _videoFrameDecodedCallback = (packetHandle, _) =>
208             {
209                 var handler = _videoFrameDecoded;
210                 if (handler != null)
211                 {
212                     Log.Debug(PlayerLog.Tag, "packet : " + packetHandle);
213                     handler.Invoke(this,
214                         new VideoFrameDecodedEventArgs(MediaPacket.From(packetHandle)));
215                 }
216                 else
217                 {
218                     MediaPacket.From(packetHandle).Dispose();
219                 }
220             };
221
222             NativePlayer.SetVideoFrameDecodedCb(Handle, _videoFrameDecodedCallback).
223                 ThrowIfFailed(this, "Failed to register the VideoFrameDecoded");
224         }
225         #endregion
226
227         #region AudioFrameDecoded event
228         /// <summary>
229         /// Occurs when a audio frame is decoded.
230         /// </summary>
231         /// <remarks>
232         ///     <para>The event handler will be executed on an internal thread.</para>
233         ///     <para>The <see cref="AudioDataDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
234         /// </remarks>
235         /// <seealso cref="AudioDataDecodedEventArgs.Packet"/>
236         /// <since_tizen> 6 </since_tizen>
237         public event EventHandler<AudioDataDecodedEventArgs> AudioDataDecoded;
238
239         private NativePlayer.AudioFrameDecodedCallback _audioFrameDecodedCallback;
240         #endregion
241
242         private void RegisterVideoStreamChangedCallback()
243         {
244             _videoStreamChangedCallback = (width, height, fps, bitrate, _) =>
245             {
246                 Log.Debug(PlayerLog.Tag, $"height={height}, width={width}, fps={fps}, bitrate={bitrate}");
247
248                 VideoStreamChanged?.Invoke(this, new VideoStreamChangedEventArgs(height, width, fps, bitrate));
249             };
250
251             NativePlayer.SetVideoStreamChangedCb(Handle, _videoStreamChangedCallback).
252                 ThrowIfFailed(this, "Failed to set the video stream changed callback");
253         }
254
255         private void RegisterBufferingCallback()
256         {
257             _bufferingProgressCallback = (percent, _) =>
258             {
259                 Log.Debug(PlayerLog.Tag, $"Buffering callback with percent { percent }");
260
261                 BufferingProgressChanged?.Invoke(this, new BufferingProgressChangedEventArgs(percent));
262             };
263
264             NativePlayer.SetBufferingCb(Handle, _bufferingProgressCallback).
265                 ThrowIfFailed(this, "Failed to set BufferingProgress");
266         }
267
268         private void RegisterMediaStreamBufferStatusCallback()
269         {
270             _mediaStreamAudioBufferStatusChangedCallback = (status, _) =>
271             {
272                 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
273                 Log.Debug(PlayerLog.Tag, "audio buffer status : " + status);
274
275                 MediaStreamAudioBufferStatusChanged?.Invoke(this,
276                     new MediaStreamBufferStatusChangedEventArgs(status));
277             };
278             _mediaStreamVideoBufferStatusChangedCallback = (status, _) =>
279             {
280                 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
281                 Log.Debug(PlayerLog.Tag, "video buffer status : " + status);
282
283                 MediaStreamVideoBufferStatusChanged?.Invoke(this,
284                     new MediaStreamBufferStatusChangedEventArgs(status));
285             };
286
287             RegisterMediaStreamBufferStatusCallback(StreamType.Audio, _mediaStreamAudioBufferStatusChangedCallback);
288             RegisterMediaStreamBufferStatusCallback(StreamType.Video, _mediaStreamVideoBufferStatusChangedCallback);
289         }
290
291         private void RegisterMediaStreamBufferStatusCallback(StreamType streamType,
292             NativePlayer.MediaStreamBufferStatusCallback cb)
293         {
294             NativePlayer.SetMediaStreamBufferStatusCb(Handle, streamType, cb).
295                 ThrowIfFailed(this, "Failed to SetMediaStreamBufferStatus");
296         }
297
298         private void RegisterMediaStreamSeekCallback()
299         {
300             _mediaStreamAudioSeekCallback = (offset, _) =>
301             {
302                 Log.Debug(PlayerLog.Tag, "audio seeking offset : " + offset);
303                 MediaStreamAudioSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
304             };
305             _mediaStreamVideoSeekCallback = (offset, _) =>
306             {
307                 Log.Debug(PlayerLog.Tag, "video seeking offset : " + offset);
308                 MediaStreamVideoSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
309             };
310
311             RegisterMediaStreamSeekCallback(StreamType.Audio, _mediaStreamAudioSeekCallback);
312             RegisterMediaStreamSeekCallback(StreamType.Video, _mediaStreamVideoSeekCallback);
313         }
314
315         private void RegisterMediaStreamSeekCallback(StreamType streamType, NativePlayer.MediaStreamSeekCallback cb)
316         {
317             NativePlayer.SetMediaStreamSeekCb(Handle, streamType, cb).
318                 ThrowIfFailed(this, "Failed to SetMediaStreamSeek");
319         }
320     }
321 }