/* * Copyright (c) 2016 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 static Interop; using System; using System.ComponentModel; using System.Diagnostics; namespace Tizen.Multimedia { public partial class Player { /// /// Occurs when the playback of a media is finished. /// /// 3 public event EventHandler PlaybackCompleted; private NativePlayer.PlaybackCompletedCallback _playbackCompletedCallback; /// /// Occurs when the playback of a media is interrupted. /// /// /// If the reason is , /// the player state will be one of , , /// or . /// /// /// 3 public event EventHandler PlaybackInterrupted; private NativePlayer.PlaybackInterruptedCallback _playbackInterruptedCallback; /// /// Occurs when any error occurs. /// /// The event handler will be executed on an internal thread. /// 3 public event EventHandler ErrorOccurred; private NativePlayer.PlaybackErrorCallback _playbackErrorCallback; /// /// Occurs when the video stream is changed. /// /// The event handler will be executed on an internal thread. /// 3 public event EventHandler VideoStreamChanged; private NativePlayer.VideoStreamChangedCallback _videoStreamChangedCallback; /// /// Occurs when the subtitle is updated. /// /// The event handler will be executed on an internal thread. /// 3 public event EventHandler SubtitleUpdated; private NativePlayer.SubtitleUpdatedCallback _subtitleUpdatedCallback; /// /// Occurs when there is a change in the buffering status of streaming. /// /// 3 public event EventHandler BufferingProgressChanged; private NativePlayer.BufferingProgressCallback _bufferingProgressCallback; private NativePlayer.PrepareCallback _prepareCallback; internal event EventHandler MediaStreamAudioBufferStatusChanged; private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamAudioBufferStatusChangedCallback; internal event EventHandler MediaStreamVideoBufferStatusChanged; private NativePlayer.MediaStreamBufferStatusCallback _mediaStreamVideoBufferStatusChangedCallback; internal event EventHandler MediaStreamAudioSeekingOccurred; private NativePlayer.MediaStreamSeekCallback _mediaStreamAudioSeekCallback; internal event EventHandler MediaStreamVideoSeekingOccurred; private NativePlayer.MediaStreamSeekCallback _mediaStreamVideoSeekCallback; private void RegisterEvents() { RegisterSubtitleUpdatedCallback(); RegisterErrorOccurredCallback(); RegisterPlaybackInterruptedCallback(); RegisterVideoStreamChangedCallback(); RegisterBufferingCallback(); RegisterMediaStreamBufferStatusCallback(); RegisterMediaStreamSeekCallback(); RegisterPlaybackCompletedCallback(); } private void RegisterSubtitleUpdatedCallback() { _subtitleUpdatedCallback = (duration, text, _) => { Log.Debug(PlayerLog.Tag, $"duration : {duration}, text : {text}"); SubtitleUpdated?.Invoke(this, new SubtitleUpdatedEventArgs(duration, text)); }; NativePlayer.SetSubtitleUpdatedCb(Handle, _subtitleUpdatedCallback). ThrowIfFailed(this, "Failed to initialize the player"); } private void RegisterPlaybackCompletedCallback() { _playbackCompletedCallback = _ => { Log.Debug(PlayerLog.Tag, "completed callback"); PlaybackCompleted?.Invoke(this, EventArgs.Empty); }; NativePlayer.SetCompletedCb(Handle, _playbackCompletedCallback). ThrowIfFailed(this, "Failed to set PlaybackCompleted"); } private void RegisterPlaybackInterruptedCallback() { _playbackInterruptedCallback = (code, _) => { if (!Enum.IsDefined(typeof(PlaybackInterruptionReason), code)) { return; } if (code == PlaybackInterruptionReason.ResourceConflict) { OnUnprepared(); } Log.Warn(PlayerLog.Tag, $"interrupted reason : {code}"); PlaybackInterrupted?.Invoke(this, new PlaybackInterruptedEventArgs(code)); }; NativePlayer.SetInterruptedCb(Handle, _playbackInterruptedCallback). ThrowIfFailed(this, "Failed to set PlaybackInterrupted"); } private void RegisterErrorOccurredCallback() { _playbackErrorCallback = (code, _) => { //TODO handle service disconnected error. Log.Warn(PlayerLog.Tag, "error code : " + code); ErrorOccurred?.Invoke(this, new PlayerErrorOccurredEventArgs((PlayerError)code)); }; NativePlayer.SetErrorCb(Handle, _playbackErrorCallback). ThrowIfFailed(this, "Failed to set PlaybackError"); } /// /// Raises the event. /// /// /// An that contains the event data. /// [EditorBrowsable(EditorBrowsableState.Never)] protected void OnErrorOccurred(PlayerErrorOccurredEventArgs e) { ErrorOccurred?.Invoke(this, e); } #region VideoFrameDecoded event /// /// Occurs when a video frame is decoded. /// /// /// The event handler will be executed on an internal thread. /// The in event args should be disposed after use. /// /// http://tizen.org/feature/multimedia.raw_video /// The required feature is not supported. /// /// 3 public event EventHandler VideoFrameDecoded; private NativePlayer.VideoFrameDecodedCallback _videoFrameDecodedCallback; #endregion #region AudioFrameDecoded event /// /// Occurs when a audio frame is decoded. /// /// /// The event handler will be executed on an internal thread. /// The in event args should be disposed after use. /// /// /// 6 public event EventHandler AudioDataDecoded; private NativePlayer.AudioFrameDecodedCallback _audioFrameDecodedCallback; #endregion private void RegisterVideoStreamChangedCallback() { _videoStreamChangedCallback = (width, height, fps, bitrate, _) => { Log.Debug(PlayerLog.Tag, $"height={height}, width={width}, fps={fps}, bitrate={bitrate}"); VideoStreamChanged?.Invoke(this, new VideoStreamChangedEventArgs(height, width, fps, bitrate)); }; NativePlayer.SetVideoStreamChangedCb(Handle, _videoStreamChangedCallback). ThrowIfFailed(this, "Failed to set the video stream changed callback"); } private void RegisterBufferingCallback() { _bufferingProgressCallback = (percent, _) => { Log.Debug(PlayerLog.Tag, $"Buffering callback with percent { percent }"); BufferingProgressChanged?.Invoke(this, new BufferingProgressChangedEventArgs(percent)); }; NativePlayer.SetBufferingCb(Handle, _bufferingProgressCallback). ThrowIfFailed(this, "Failed to set BufferingProgress"); } private void RegisterMediaStreamBufferStatusCallback() { _mediaStreamAudioBufferStatusChangedCallback = (status, _) => { Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status)); Log.Debug(PlayerLog.Tag, "audio buffer status : " + status); MediaStreamAudioBufferStatusChanged?.Invoke(this, new MediaStreamBufferStatusChangedEventArgs(status)); }; _mediaStreamVideoBufferStatusChangedCallback = (status, _) => { Debug.Assert(Enum.IsDefined(typeof(MediaStreamBufferStatus), status)); Log.Debug(PlayerLog.Tag, "video buffer status : " + status); MediaStreamVideoBufferStatusChanged?.Invoke(this, new MediaStreamBufferStatusChangedEventArgs(status)); }; RegisterMediaStreamBufferStatusCallback(StreamType.Audio, _mediaStreamAudioBufferStatusChangedCallback); RegisterMediaStreamBufferStatusCallback(StreamType.Video, _mediaStreamVideoBufferStatusChangedCallback); } private void RegisterMediaStreamBufferStatusCallback(StreamType streamType, NativePlayer.MediaStreamBufferStatusCallback cb) { NativePlayer.SetMediaStreamBufferStatusCb(Handle, streamType, cb). ThrowIfFailed(this, "Failed to SetMediaStreamBufferStatus"); } private void RegisterMediaStreamSeekCallback() { _mediaStreamAudioSeekCallback = (offset, _) => { Log.Debug(PlayerLog.Tag, "audio seeking offset : " + offset); MediaStreamAudioSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset)); }; _mediaStreamVideoSeekCallback = (offset, _) => { Log.Debug(PlayerLog.Tag, "video seeking offset : " + offset); MediaStreamVideoSeekingOccurred?.Invoke(this, new MediaStreamSeekingOccurredEventArgs(offset)); }; RegisterMediaStreamSeekCallback(StreamType.Audio, _mediaStreamAudioSeekCallback); RegisterMediaStreamSeekCallback(StreamType.Video, _mediaStreamVideoSeekCallback); } private void RegisterMediaStreamSeekCallback(StreamType streamType, NativePlayer.MediaStreamSeekCallback cb) { NativePlayer.SetMediaStreamSeekCb(Handle, streamType, cb). ThrowIfFailed(this, "Failed to SetMediaStreamSeek"); } } }