2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 using System.Threading.Tasks;
18 using System.Runtime.InteropServices;
19 using System.Diagnostics;
21 using System.Threading;
24 namespace Tizen.Multimedia
26 public partial class Player
29 /// Occurs when the playback of a media is finished.
31 public event EventHandler<EventArgs> PlaybackCompleted;
32 private NativePlayer.PlaybackCompletedCallback _playbackCompletedCallback;
35 /// Occurs when the playback of a media is interrupted.
37 public event EventHandler<PlaybackInterruptedEventArgs> PlaybackInterrupted;
38 private NativePlayer.PlaybackInterruptedCallback _playbackInterruptedCallback;
41 /// Occurs when any error occurs.
43 /// <remarks>The event handler will be executed on an internal thread.</remarks>
44 public event EventHandler<PlayerErrorOccurredEventArgs> ErrorOccurred;
45 private NativePlayer.PlaybackErrorCallback _playbackErrorCallback;
48 /// Occurs when the video stream is changed.
50 /// <remarks>The event handler will be executed on an internal thread.</remarks>
51 public event EventHandler<VideoStreamChangedEventArgs> VideoStreamChanged;
52 private NativePlayer.VideoStreamChangedCallback _videoStreamChangedCallback;
55 /// Occurs when the subtitle is updated.
57 /// <remarks>The event handler will be executed on an internal thread.</remarks>
58 public event EventHandler<SubtitleUpdatedEventArgs> SubtitleUpdated;
59 private NativePlayer.SubtitleUpdatedCallback _subtitleUpdatedCallback;
62 /// Occurs when there is a change in the buffering status of streaming.
64 public event EventHandler<BufferingProgressChangedEventArgs> BufferingProgressChanged;
65 private NativePlayer.BufferingProgressCallback _bufferingProgressCallback;
67 internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamAudioBufferStatusChanged;
68 private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamAudioBufferStatusChangedCallback;
70 internal event EventHandler<MediaStreamBufferStatusChangedEventArgs> MediaStreamVideoBufferStatusChanged;
71 private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamVideoBufferStatusChangedCallback;
73 internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamAudioSeekingOccurred;
74 private NativePlayer.MediaStreamSeekCallback _mediaStreamAudioSeekCallback;
76 internal event EventHandler<MediaStreamSeekingOccurredEventArgs> MediaStreamVideoSeekingOccurred;
77 private NativePlayer.MediaStreamSeekCallback _mediaStreamVideoSeekCallback;
79 private bool _callbackRegistered;
81 private void RegisterEvents()
83 if (_callbackRegistered)
87 RegisterSubtitleUpdatedCallback();
88 RegisterErrorOccurredCallback();
89 RegisterPlaybackInterruptedCallback();
90 RegisterVideoStreamChangedCallback();
91 RegisterBufferingCallback();
92 RegisterMediaStreamBufferStatusCallback();
93 RegisterMediaStreamSeekCallback();
94 RegisterPlaybackCompletedCallback();
96 _callbackRegistered = true;
99 private void RegisterSubtitleUpdatedCallback()
101 _subtitleUpdatedCallback = (duration, text, _) =>
103 Log.Debug(PlayerLog.Tag, "duration : " + duration + ", text : " + text);
104 SubtitleUpdated?.Invoke(this, new SubtitleUpdatedEventArgs(duration, text));
107 NativePlayer.SetSubtitleUpdatedCb(Handle, _subtitleUpdatedCallback).
108 ThrowIfFailed("Failed to initialize the player");
111 private void RegisterPlaybackCompletedCallback()
113 _playbackCompletedCallback = _ =>
115 Log.Debug(PlayerLog.Tag, "completed callback");
116 PlaybackCompleted?.Invoke(this, EventArgs.Empty);
118 NativePlayer.SetCompletedCb(Handle, _playbackCompletedCallback).
119 ThrowIfFailed("Failed to set PlaybackCompleted");
122 private void RegisterPlaybackInterruptedCallback()
124 _playbackInterruptedCallback = (code, _) =>
126 if (!Enum.IsDefined(typeof(PlaybackInterruptionReason), code))
131 if (code == PlaybackInterruptionReason.ResourceConflict)
136 Log.Warn(PlayerLog.Tag, "interrupted reason : " + code);
137 PlaybackInterrupted?.Invoke(this, new PlaybackInterruptedEventArgs(code));
140 NativePlayer.SetInterruptedCb(Handle, _playbackInterruptedCallback).
141 ThrowIfFailed("Failed to set PlaybackInterrupted");
144 private void RegisterErrorOccurredCallback()
146 _playbackErrorCallback = (code, _) =>
148 //TODO handle service disconnected error.
149 Log.Warn(PlayerLog.Tag, "error code : " + code);
150 ErrorOccurred?.Invoke(this, new PlayerErrorOccurredEventArgs((PlayerError)code));
153 NativePlayer.SetErrorCb(Handle, _playbackErrorCallback).
154 ThrowIfFailed("Failed to set PlaybackError");
157 #region VideoFrameDecoded event
159 private EventHandler<VideoFrameDecodedEventArgs> _videoFrameDecoded;
161 private NativePlayer.VideoFrameDecodedCallback _videoFrameDecodedCallback;
164 /// Occurs when a video frame is decoded.
167 /// <para>The event handler will be executed on an internal thread.</para>
168 /// <para>The <see cref="VideoFrameDecodedEventArgs.Packet"/> in event args should be disposed after use.</para>
170 /// <feature>http://tizen.org/feature/multimedia.raw_video</feature>
171 /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
172 /// <seealso cref="VideoFrameDecodedEventArgs.Packet"/>
173 public event EventHandler<VideoFrameDecodedEventArgs> VideoFrameDecoded
177 ValidationUtil.ValidateFeatureSupported(Features.RawVideo);
179 _videoFrameDecoded += value;
183 ValidationUtil.ValidateFeatureSupported(Features.RawVideo);
185 _videoFrameDecoded -= value;
189 private void RegisterVideoFrameDecodedCallback()
191 _videoFrameDecodedCallback = (packetHandle, _) =>
193 var handler = _videoFrameDecoded;
196 Log.Debug(PlayerLog.Tag, "packet : " + packetHandle);
198 new VideoFrameDecodedEventArgs(MediaPacket.From(packetHandle)));
202 MediaPacket.From(packetHandle).Dispose();
206 NativePlayer.SetVideoFrameDecodedCb(Handle, _videoFrameDecodedCallback).
207 ThrowIfFailed("Failed to register the VideoFrameDecoded");
211 private void RegisterVideoStreamChangedCallback()
213 ValidatePlayerState(PlayerState.Idle);
215 _videoStreamChangedCallback = (width, height, fps, bitrate, _) =>
217 Log.Debug(PlayerLog.Tag, "height : " + height + ", width : " + width
218 + ", fps : " + fps + ", bitrate : " + bitrate);
220 VideoStreamChanged?.Invoke(this, new VideoStreamChangedEventArgs(height, width, fps, bitrate));
223 NativePlayer.SetVideoStreamChangedCb(Handle, _videoStreamChangedCallback).
224 ThrowIfFailed("Failed to set the video stream changed callback");
227 private void RegisterBufferingCallback()
229 _bufferingProgressCallback = (percent, _) =>
231 Log.Debug(PlayerLog.Tag, $"Buffering callback with percent { percent }");
232 BufferingProgressChanged?.Invoke(this, new BufferingProgressChangedEventArgs(percent));
235 NativePlayer.SetBufferingCb(Handle, _bufferingProgressCallback).
236 ThrowIfFailed("Failed to set BufferingProgress");
239 private void RegisterMediaStreamBufferStatusCallback()
241 _mediaStreamAudioBufferStatusChangedCallback = (status, _) =>
243 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
244 Log.Debug(PlayerLog.Tag, "audio buffer status : " + status);
245 MediaStreamAudioBufferStatusChanged?.Invoke(this,
246 new MediaStreamBufferStatusChangedEventArgs(status));
248 _mediaStreamVideoBufferStatusChangedCallback = (status, _) =>
250 Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status));
251 Log.Debug(PlayerLog.Tag, "video buffer status : " + status);
252 MediaStreamVideoBufferStatusChanged?.Invoke(this,
253 new MediaStreamBufferStatusChangedEventArgs(status));
256 RegisterMediaStreamBufferStatusCallback(StreamType.Audio, _mediaStreamAudioBufferStatusChangedCallback);
257 RegisterMediaStreamBufferStatusCallback(StreamType.Video, _mediaStreamVideoBufferStatusChangedCallback);
260 private void RegisterMediaStreamBufferStatusCallback(StreamType streamType,
261 NativePlayer.MediaStreamBufferStatusCallback cb)
263 NativePlayer.SetMediaStreamBufferStatusCb(Handle, streamType, cb).
264 ThrowIfFailed("Failed to SetMediaStreamBufferStatus");
267 private void RegisterMediaStreamSeekCallback()
269 _mediaStreamAudioSeekCallback = (offset, _) =>
271 Log.Debug(PlayerLog.Tag, "audio seeking offset : " + offset);
272 MediaStreamAudioSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
274 _mediaStreamVideoSeekCallback = (offset, _) =>
276 Log.Debug(PlayerLog.Tag, "video seeking offset : " + offset);
277 MediaStreamVideoSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset));
280 RegisterMediaStreamSeekCallback(StreamType.Audio, _mediaStreamAudioSeekCallback);
281 RegisterMediaStreamSeekCallback(StreamType.Video, _mediaStreamVideoSeekCallback);
284 private void RegisterMediaStreamSeekCallback(StreamType streamType, NativePlayer.MediaStreamSeekCallback cb)
286 NativePlayer.SetMediaStreamSeekCb(Handle, streamType, cb).
287 ThrowIfFailed("Failed to SetMediaStreamSeek");