| File: System\Windows\Media\mediaeventshelper.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // using System.Text; using MS.Internal; using System.Windows.Threading; using System.IO; namespace System.Windows.Media { #region MediaEventsHelper /// <summary> /// MediaEventsHelper /// Provides helper methods for media event related tasks /// </summary> internal class MediaEventsHelper : IInvokable { #region Constructors and Finalizers /// <summary> /// Constructor /// </summary> internal MediaEventsHelper(MediaPlayer mediaPlayer) { _mediaOpened = new DispatcherOperationCallback(OnMediaOpened); this.DispatcherMediaOpened += _mediaOpened; _mediaFailed = new DispatcherOperationCallback(OnMediaFailed); this.DispatcherMediaFailed += _mediaFailed; _mediaPrerolled = new DispatcherOperationCallback(OnMediaPrerolled); this.DispatcherMediaPrerolled += _mediaPrerolled; _mediaEnded = new DispatcherOperationCallback(OnMediaEnded); this.DispatcherMediaEnded += _mediaEnded; _bufferingStarted = new DispatcherOperationCallback(OnBufferingStarted); this.DispatcherBufferingStarted += _bufferingStarted; _bufferingEnded = new DispatcherOperationCallback(OnBufferingEnded); this.DispatcherBufferingEnded += _bufferingEnded; _scriptCommand = new DispatcherOperationCallback(OnScriptCommand); this.DispatcherScriptCommand += _scriptCommand; _newFrame = new DispatcherOperationCallback(OnNewFrame); this.DispatcherMediaNewFrame += _newFrame; SetSender(mediaPlayer); } #endregion #region Static Methods /// <summary> /// Create /// </summary> internal static void CreateMediaEventsHelper(MediaPlayer mediaPlayer, out MediaEventsHelper eventsHelper, out SafeMILHandle unmanagedProxy) { eventsHelper = new MediaEventsHelper(mediaPlayer); // Created with ref count = 1. Since this object does not hold on // to the unmanaged proxy, the lifetime is now controlled by whoever // called CreateMediaEventsHelper. unmanagedProxy = EventProxyWrapper.CreateEventProxyWrapper(eventsHelper); } #endregion #region Internal Methods / Properties / Events /// <summary> /// Changes the sender of all events /// </summary> internal void SetSender(MediaPlayer sender) { Debug.Assert((sender != null), "Sender is null"); Debug.Assert((sender.Dispatcher != null), "Dispatcher is null"); _sender = sender; _dispatcher = sender.Dispatcher; } /// <summary> /// Raised when error is encountered. /// </summary> internal event EventHandler<ExceptionEventArgs> MediaFailed { add { _mediaFailedHelper.AddEvent(value); } remove { _mediaFailedHelper.RemoveEvent(value); } } /// <summary> /// Raised when media loading is complete /// </summary> internal event EventHandler MediaOpened { add { _mediaOpenedHelper.AddEvent(value); } remove { _mediaOpenedHelper.RemoveEvent(value); } } /// <summary> /// Raised when media prerolling is complete /// </summary> internal event EventHandler MediaPrerolled { add { _mediaPrerolledHelper.AddEvent(value); } remove { _mediaPrerolledHelper.RemoveEvent(value); } } /// <summary> /// Raised when media playback is finished /// </summary> internal event EventHandler MediaEnded { add { _mediaEndedHelper.AddEvent(value); } remove { _mediaEndedHelper.RemoveEvent(value); } } /// <summary> /// Raised when buffering begins /// </summary> internal event EventHandler BufferingStarted { add { _bufferingStartedHelper.AddEvent(value); } remove { _bufferingStartedHelper.RemoveEvent(value); } } /// <summary> /// Raised when buffering is complete /// </summary> internal event EventHandler BufferingEnded { add { _bufferingEndedHelper.AddEvent(value); } remove { _bufferingEndedHelper.RemoveEvent(value); } } /// <summary> /// Raised when a script command that is embedded in the media is reached. /// </summary> internal event EventHandler<MediaScriptCommandEventArgs> ScriptCommand { add { _scriptCommandHelper.AddEvent(value); } remove { _scriptCommandHelper.RemoveEvent(value); } } /// <summary> /// Raised when a requested media frame is reached. /// </summary> internal event EventHandler NewFrame { add { _newFrameHelper.AddEvent(value); } remove { _newFrameHelper.RemoveEvent(value); } } internal void RaiseMediaFailed(Exception e) { if (DispatcherMediaFailed != null) { _dispatcher.BeginInvoke( DispatcherPriority.Normal, DispatcherMediaFailed, new ExceptionEventArgs(e)); } } #endregion #region IInvokable /// <summary> /// Raises an event /// </summary> void IInvokable.RaiseEvent(byte[] buffer, int cb) { const int S_OK = 0; AVEvent avEventType = AVEvent.AVMediaNone; int failureHr = S_OK; int size = 0; // // Minumum size is the event enum, the error hresult and two // string lengths (as integers) // size = sizeof(int) * 4; // // The data could be larger, that is benign, in the case that we have // strings appended it will be. // if (cb < size) { Debug.Assert((cb == size), "Invalid event packet"); return; } MemoryStream memStream = new MemoryStream(buffer); using (BinaryReader reader = new BinaryReader(memStream)) { // // Unpack the event and the errorHResult // avEventType = (AVEvent)reader.ReadUInt32(); failureHr = (int)reader.ReadUInt32(); switch(avEventType) { case AVEvent.AVMediaOpened: if (DispatcherMediaOpened != null) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, DispatcherMediaOpened, null); } break; case AVEvent.AVMediaFailed: RaiseMediaFailed(HRESULT.ConvertHRToException(failureHr)); break; case AVEvent.AVMediaBufferingStarted: if (DispatcherBufferingStarted != null) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, DispatcherBufferingStarted, null); } break; case AVEvent.AVMediaBufferingEnded: if (DispatcherBufferingEnded != null) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, DispatcherBufferingEnded, null); } break; case AVEvent.AVMediaEnded: if (DispatcherMediaEnded != null) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, DispatcherMediaEnded, null); } break; case AVEvent.AVMediaPrerolled: if (DispatcherMediaPrerolled != null) { _dispatcher.BeginInvoke(DispatcherPriority.Normal, DispatcherMediaPrerolled, null); } break; case AVEvent.AVMediaScriptCommand: HandleScriptCommand(reader); break; case AVEvent.AVMediaNewFrame: if (DispatcherMediaNewFrame != null) { // // We set frame updates to background because media is high frequency and bandwidth enough // to interfere dramatically with input. // _dispatcher.BeginInvoke(DispatcherPriority.Background, DispatcherMediaNewFrame, null); } break; default: // // Default case intentionally not handled. // break; } } } #endregion #region Private Methods / Events /// <summary> /// Handle the parsing of script commands coming up from media that /// supports them. Then binary reader at this point will be positioned /// at the first of the string lengths encoded in the structure. /// </summary> private void HandleScriptCommand( BinaryReader reader ) { int parameterTypeLength = (int)reader.ReadUInt32(); int parameterValueLength = (int)reader.ReadUInt32(); if (DispatcherScriptCommand != null) { string parameterType = GetStringFromReader(reader, parameterTypeLength); string parameterValue = GetStringFromReader(reader, parameterValueLength); _dispatcher.BeginInvoke( DispatcherPriority.Normal, DispatcherScriptCommand, new MediaScriptCommandEventArgs( parameterType, parameterValue)); } } /// <summary> /// Reads in a sequence of unicode characters from a binary /// reader and inserts them into a StringBuilder. From this /// a string is returned. /// </summary> private string GetStringFromReader( BinaryReader reader, int stringLength ) { // // Set the initial capacity of the string builder to stringLength // StringBuilder stringBuilder = new StringBuilder(stringLength) { // // Also set the actual length, this allows the string to be indexed // to that point. // Length = stringLength }; for (int i = 0; i < stringLength; i++) { stringBuilder[i] = (char)reader.ReadUInt16(); } return stringBuilder.ToString(); } /// <summary> /// Media Opened event comes through here /// </summary> /// <param name="o">Null argument</param> private object OnMediaOpened(object o) { _mediaOpenedHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// MediaPrerolled event comes through here /// </summary> /// <param name="o">Null argument</param> private object OnMediaPrerolled(object o) { _mediaPrerolledHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// MediaEnded event comes through here /// </summary> /// <param name="o">Null argument</param> private object OnMediaEnded(object o) { _mediaEndedHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// BufferingStarted event comes through here /// </summary> /// <param name="o">Null argument</param> private object OnBufferingStarted(object o) { _bufferingStartedHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// BufferingEnded event comes through here /// </summary> /// <param name="o">Null argument</param> private object OnBufferingEnded(object o) { _bufferingEndedHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// MediaFailed event comes through here /// </summary> /// <param name="o">EventArgs</param> private object OnMediaFailed(object o) { ExceptionEventArgs e = (ExceptionEventArgs)o; _mediaFailedHelper.InvokeEvents(_sender, e); return null; } /// <summary> /// Script commands come through here. /// </summary> /// <param name ="o">EventArgs</param> private object OnScriptCommand(object o) { MediaScriptCommandEventArgs e = (MediaScriptCommandEventArgs)o; _scriptCommandHelper.InvokeEvents(_sender, e); return null; } /// <summary> /// New frames come through here. /// </summary> private object OnNewFrame(object e) { _newFrameHelper.InvokeEvents(_sender, null); return null; } /// <summary> /// Raised by a media when it encounters an error. /// </summary> /// <remarks> /// Argument passed into the callback is a System.Exception /// </remarks> private event DispatcherOperationCallback DispatcherMediaFailed; /// <summary> /// Raised by a media when its done loading. /// </summary> private event DispatcherOperationCallback DispatcherMediaOpened; /// <summary> /// Raised by a media when its done prerolling. /// </summary> private event DispatcherOperationCallback DispatcherMediaPrerolled; /// <summary> /// Raised by a media when its done playback. /// </summary> private event DispatcherOperationCallback DispatcherMediaEnded; /// <summary> /// Raised by a media when buffering begins. /// </summary> private event DispatcherOperationCallback DispatcherBufferingStarted; /// <summary> /// Raised by a media when buffering finishes. /// </summary> private event DispatcherOperationCallback DispatcherBufferingEnded; /// <summary> /// Raised by media when a particular scripting event is received. /// </summary> private event DispatcherOperationCallback DispatcherScriptCommand; /// <summary> /// Raised whenever a new frame is displayed that has been requested. /// This is only required for effects. /// </summary> private event DispatcherOperationCallback DispatcherMediaNewFrame; #endregion #region Private Data Members /// <summary> /// Sender of all events /// </summary> private MediaPlayer _sender; /// <summary> /// Dispatcher of this object /// </summary> private Dispatcher _dispatcher; /// <summary> /// for catching MediaOpened events /// </summary> private DispatcherOperationCallback _mediaOpened; /// <summary> /// for catching MediaFailed events /// </summary> private DispatcherOperationCallback _mediaFailed; /// <summary> /// for catching MediaPrerolled events /// </summary> private DispatcherOperationCallback _mediaPrerolled; /// <summary> /// for catching MediaEnded events /// </summary> private DispatcherOperationCallback _mediaEnded; /// <summary> /// for catching BufferingStarted events /// </summary> private DispatcherOperationCallback _bufferingStarted; /// <summary> /// for catching BufferingEnded events /// </summary> private DispatcherOperationCallback _bufferingEnded; /// <summary> /// for catching script command events. /// </summary> private DispatcherOperationCallback _scriptCommand; /// <summary> /// For catching new frame notifications. /// </summary> private DispatcherOperationCallback _newFrame; /// <summary> /// Helper for MediaFailed events /// </summary> private UniqueEventHelper<ExceptionEventArgs> _mediaFailedHelper = new UniqueEventHelper<ExceptionEventArgs>(); /// <summary> /// Helper for MediaOpened events /// </summary> private UniqueEventHelper _mediaOpenedHelper = new UniqueEventHelper(); /// <summary> /// Helper for MediaPrerolled events /// </summary> private UniqueEventHelper _mediaPrerolledHelper = new UniqueEventHelper(); /// <summary> /// Helper for MediaEnded events /// </summary> private UniqueEventHelper _mediaEndedHelper = new UniqueEventHelper(); /// <summary> /// Helper for BufferingStarted events /// </summary> private UniqueEventHelper _bufferingStartedHelper = new UniqueEventHelper(); /// <summary> /// Helper for BufferingEnded events /// </summary> private UniqueEventHelper _bufferingEndedHelper = new UniqueEventHelper(); /// <summary> /// Helper for the script command events /// </summary> private UniqueEventHelper<MediaScriptCommandEventArgs> _scriptCommandHelper = new UniqueEventHelper<MediaScriptCommandEventArgs>(); /// <summary> /// Helper for the NewFrame events. /// </summary> private UniqueEventHelper _newFrameHelper = new UniqueEventHelper(); #endregion } #endregion };