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