Fix: Allow rewind of Mp3MediaStreamSource back to start

My comment at:

https://github.com/loarabia/ManagedMediaHelpers/issues/16

While trying to use Mp3MediaSource at ClipFlair Studio’s AudioRecorder control (http://clipflair.codeplex.com), I noticed that when I was doing Stop() at MediaElement and then Play() it kept on playing from where it was before at Mp3MediaStreamSource

So I did the following fix:

 

1) added these fields

    /// <summary>
    /// The first known frame (for rewind)
    /// </summary>     
    private MpegFrame firstFrame;

    /// <summary>
    /// The first audio stream position (for rewind)
    /// </summary>
    private long firstAudioStreamPosition;

 

2) added to the end of ReadPastId3v2TagsCallback:

this.firstFrame = mpegLayer3Frame; //keeping the 1st frame position for rewinding
this.firstAudioStreamPosition = audioStream.Position;

 

3) changed SeekAsync:

    /// <summary>
    /// <para>
    /// Only supporting seeking back to start of the stream 
/// (e.g. when doing MediaElement.Stop()). /// </para> /// <para> /// In a fuller MediaStreamSource, the logic here would be to actually seek to /// the correct mpeg frame matching the seekToTime passed in. /// </para> /// </summary> /// <param name="seekToTime"> /// The time to seek to (in 100-nanosecond units [hns]) /// </param> protected override void SeekAsync(long seekToTime) { /* if (seekToTime > this.trackDuration.TotalMilliseconds * 10) { throw new InvalidOperationException(
"The seek position is beyond the length of the stream"); } */ if (seekToTime != 0) //only supporting rewinding back to start throw new InvalidOperationException(
"Only supporting seeking back to start of the stream"); else { this.currentFrame = firstFrame; this.currentFrameStartPosition = MpegFrame.FrameHeaderSize; this.audioStream.Position = firstAudioStreamPosition; } this.ReportSeekCompleted(seekToTime); }

 

note that I changed the documentation for that method to say that time passed to it is in 100 ns units, not in ns units (according to WaveMediaStreamSource code that I found, unless that one has it wrong)

Gotcha: MediaElement must be in visual tree for MediaOpened, MediaEnded to be fired

At ClipFlair’s AudioRecorderControl (used in Captions/Revoicing component of ClipFlair Studio), I use the following code to initialize a MediaElement to use for playback.

After a long time a found out that if the MediaElement is not in the visual tree (for example defined in XAML, or defined in code and then added to the visual tree), then it will not always fire MediaOpened and MediaEnded events, which are crucial if you want to have a two-state Play/Stop button (a ToggleButton).

 

public MediaElement Player
{   get { return player; }   
set {    
if (player != null) {      
player.MediaOpened -= MediaElement_MediaOpened;
player.MediaEnded -= MediaElement_MediaEnded;    
}    

player = value;


    
if (player != null)  {      
player.MediaOpened += MediaElement_MediaOpened;
        player.MediaEnded += MediaElement_MediaEnded;

       player.AutoPlay = false;
       player.PlaybackRate = 1.0;
       player.Balance = 0;
       Volume = DEFAULT_VOLUME;  
  }
  } }

 

protected void MediaElement_MediaOpened(object sender, RoutedEventArgs e)
{   
try   {    
//player.Position = TimeSpan.Zero;     
player.Stop(); //this stops current playback (if any) and rewinds
    player.Play();  
}   catch (Exception ex)   {    
PlayCommandUncheck(); //depress playback toggle button
//don't talk to ToggleButton directly    
Status = MSG_PLAY_FAILED + ex.Message;  
} }
 

protected void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
  PlayCommandUncheck(); //depress play button to stop playback
//don't talk to ToggleButton directly }

Gotcha: MediaElement AutoPlay faster than doing Play at MediaOpened

Just added the following comment to: https://github.com/loarabia/ManagedMediaHelpers/issues/15

Managed Media Helpers contains the very useful Mp3MediaSource class for .NET / Silverlight / Windows Phone.

Added compile-time SWITCHES and respective code to Silverlight demo code for PRELOAD (into memory stream) and AUTOPLAY (this was a bit tricky, need to call Play at MediaOpened event, not right after setting the source to the MediaElement).

Also seems to be 2-3 sec slower than AutoPlay (!) irrespective of using PRELOAD. Maybe it is faster to set the source again every time you want to play and just keep AutoPlay=true

Update: had a bug at the following code, obviously you first must set the MediaOpened event handler, then set the Source to the MediaPlayer. Also, one could set that handler once at the InitializeComponent method.

 

//———————————————————————–
// <copyright file="Page.xaml.cs" company="Larry Olson">
// (c) Copyright Larry Olson.
// This source is subject to the Microsoft Public License (Ms-PL)
// See http://code.msdn.microsoft.com/ManagedMediaHelpers/Project/License.aspx
// All other rights reserved.
// </copyright>
//
// Edited by George Birbilis (http://zoomicon.com)
//———————————————————————–

#define AUTOPLAY
//#define PRELOAD

namespace Mp3MediaStreamSourceDemo
{
  using Media;
  using System;
  using System.IO;
  using System.Windows;
  using System.Windows.Controls;

    /// <summary>
    /// A Page of a Silvelight Application.
    /// </summary>
    public partial class Page : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the Page class.
        /// </summary>
        public Page()
        {
            InitializeComponent();

            me.Volume = 1.0; //set max volume
           
            #if !AUTOPLAY
            me.AutoPlay = false;

             me.MediaOpened += (s, e) =>
            {
                //me.Position = TimeSpan.Zero;
                me.Stop(); //this stops current playback (if any) and rewinds back to start
                //me.PlaybackRate = 1.0;
                try
                {
                    me.Play();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            };  
            #endif
        }

        /// <summary>
        /// Event handler for the Button on the Page.
        /// </summary>
        /// <param name="sender">
        /// The button which was clicked.
        /// </param>
        /// <param name="e">
        /// The state when this event was generated.
        /// </param>
        private void OpenMedia(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.ShowDialog();

            Stream data = ofd.File.OpenRead();

            #if PRELOAD
            Stream m = new MemoryStream((int)ofd.File.Length);
            data.CopyTo(m);
            m.Position = 0;
            data = m;
            #endif

 

             Mp3MediaStreamSource mediaSource = new Mp3MediaStreamSource(data);     
            me.SetSource(mediaSource);
        }
    }
}

HowTo: Use WordPress Permalinks on IIS

at http://zachis.it/blog/7-dangers-of-using-windows-server-on-a-wordpress-installation/

the thing that guy says about Permalinks isn’t accurate at all (not that the other things that he says are any accurate that is). WordPress Codex have documentation on how to configure URL rewriting in web.config that is necessery for Permalinks to work in IIS.

e.g. at http://ClipFlair.net, if you press the "about" icon you’re taken to a WordPress site that runs on IIS and uses permalinks fine and hides the index.php too from the URL

in its web.config I have the following:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>

        <httpErrors>
            <remove statusCode="404" subStatusCode="-1" />
            <error statusCode="404" prefixLanguageFilePath="" path="/index.php?error=404" responseMode="ExecuteURL" />
        </httpErrors>

        <!– Needed for WordPress Permalinks –>
        <rewrite>
            <rules>

                <rule name="Main Rule" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                    <!– <action type="Rewrite" url="index.php/{R:0}" /> –>
                    <action type="Rewrite" url="index.php" />
                </rule>

            </rules>
        </rewrite>

        <defaultDocument>
            <files>
                <clear />
                <add value="index.html" />
                <add value="index.php" />
                <add value="default.aspx" />
            </files>
        </defaultDocument>

    </system.webServer>
</configuration>

Fix: Hypelinks not clickable in RichTextBox under Silverlight

Just fixed a nasty bug in ClipFlair Studio (http://studio.clipflair.net), where one couldn’t click hyperlinks in the Text component when set at ReadOnly mode. In that mode hyperlinks should open up new web pages (in Edit mode you can edit/remove them only of course), but instead when clicked they would show something like a focus rectangle (which they normally never show).

image

The situation was hard to debug since it wasn’t obvious what had caused the issue (it was working some time ago). I eventually found out that when the RichTextBox in Silverlight (may occur in WPF and WinRT too, haven’t tried) has a Transparent background, then Hyperlinks in it let MouseLeftButtonDown events pass through, so OnMouseLeftButtonDown will fire at their visual parent (or other visual ancestor) if no component in the visual chain marks the event as handled (such events bubble up towards the top of the visual hierarchy/containment chain).

This shouldn’t be much of a problem, if there wasn’t another issue, where if the ancestor called CaptureMouse in their OnMouseLeftButtonDown overriden method (from Control class), which is usual in mouse dragging code (in my case it was a FloatingWindow [TextWindow] that was the visual ancestor of RichTextBox), the hyperlink fails to fire when clicked and shows that weird solid-line border arround it instead.

The fix was easy once I knew what was happening, I attached a MouseLeftButtonDown event handler to the RichTextBox (if one was subclassing it [assuming it allows to do so] they could also have opted to add an overriden OnMouseLeftButtonDown method) that sets Handled property of the event parameter to true to consume it. The fix is available at CodePlex.

One can verify that the fix works now by downloading a sample ClipFlair Activity from https://www.dropbox.com/s/1zr36190xb0m6vk/Test_Text_URLs.clipflair and opening it in ClipFlair Studio. Can also download and build/run the source code of the previous broken version 1faaa8b35749 and test with that save activity file to see that the URLs didn’t open before when clicked but showed a rectangle arround them intead.

image

HowTo: use PivotViewer in WPF

PivotViewer is an impressive Silverlight control (see my usage at http://gallery.clipflair.net), however Microsoft never released it for WPF.

One could work arround this by embedding Silverlight in their WPF app using the WebBrowser control and talking to it via the JavaScript Bridge of Silverlight, however they could also embed one of those HTML5 PivotViewer-compatible controls that have surfaced in recent years.

Apart from LobsterPot’s HTML5 PivotViewer and its older free version, for another HTML5 PivotViewer (and also a DeepZoom implementation for HTML5) you could host that comes from former SeaDragon team members at Microsoft and seems to work very well see:

http://seajax.github.io/

https://github.com/seajax/seajax/tree/master/v2/app/pivot

https://github.com/seajax/seajax/blob/master/v2/app/pivot/quickstart.html

https://github.com/seajax/seajax

Note that the WebBrowser control uses IE7 or something as HTML engine by default and you need some meta markup at the top of your HTML to tell it to use Edge mode – the latest IE engine that is installed)

<meta http-equiv="X-UA-Compatible" content="IE=edge">

HowTo: Tell IE to use compatibility mode without editing your web pages

at http://www.mono-software.com/Mono/Pages/Discussion/dtopic/_YyUBIlx5kiqHaNqAQeltg/br-brake-bug-in-IE11-and-clipflair-text-editor/

one reads:

We are using Telerik’s rich text editor (RadEditor), and it seems that RadEditor has specific behaviour regarding insertion of break tags.

To circumvent this issue please try to add host header in ISS 7 (website level):

Name = "X-UA-Compatible"
Value = "IE=EmulateIE10"

Or, you can insert Html Meta tag on a PreRender event (of Page that uses RadEditor):

HtmlMeta meta = new HtmlMeta();

meta.Attributes.Add("http-equiv", "X-UA-Compatible");

meta.Attributes.Add("content", "IE=EmulateIE10");

Page.Header.Controls.Add(meta);

 

This is a very handy trick, one can open up a website at IIS console and open HTTP Response Headers node and then add the Name / Value pair X-UA-Compatible / IE=EmulateIE10 to force say Internet Explorer 11 to behave like Internet Explorer 10

To confirm it works, press F12 to show developer tools in IE11 and see at the right that it says “IE10” instead of “Edge” at the HTML engine selection dropdown list (compatibility mode).

 

Screenshot 2014-08-22 19.05.29

Follow

Get every new post delivered to your Inbox.

Join 946 other followers

%d bloggers like this: