Hooray!

I have tonight, finally got DTS MKVs working reliably in MediaPortal. It was actually a very simple solution in the end. I did a little experimentation around using the SPDIF output in my existing audio filter. I found that if I told it to decode to 5.1 it worked fine. So it was a problem with the audio filter passing audio straight onto the SPDIF output.

Since, I’d used AC3Filter in the past I simply installed that, set it up for my amp (just checking which rates my amp would support via the SPDIF check utility provided with AC3Filter), and I was away.

So, I now have glorious DTS sound again, the only difference from the last time I used AC3Filter on my previous Media Centre PC is that this one can play back 1080p video files easily.

Update (3rd August 2010)

Actually they don’t work! I thought they did, but only a few select ones did. Oddly my other media PC works perfectly. So, I’ve swapped them around and the fully working one is now in the lounge. It plays everything back without any problems at all. The plan is to clone that hard drive in order to get the other PC to a known working state.

I recently got myself (as a present) a nice new Denon AVR 1910 AV Receiver, which has HDMI video switching. So I duly plugged my HTPC into one of the HDMI inputs and hooked my HDTV up to the HDMI monitor out. All was well, everything worked as it did before. That is after I’d spent a few hours setting the amp up.

Whilst fiddling around with my new toy, I switched the amp to a different HDMI video input and then back to the HTPC input. Whoa, what’s this black border around the whole picture?! I have a Toshiba 42WLT66 which is a 1080i panel, that means it’s got a native resolution of 1920×1080 (albeit only capable of interlaced video). So, I’ve got my PC configured to 1920×1080 @ 25Hz. But when I checked the video settings, it had defaulted back to 30 Hz, hence the black border.

I found that if I switched the amp on first and let it go through the startup routine, then switch the TV on and then the HTPC all was well. Anything other than that order and the HTPC defaulted to 30Hz, which was useless for my purposes. So, I’ve since spent a lot of time researching different ways of fixing the problem on the web. I even installed the latest ATI Catalyst drivers and Catalyst Control Centre, but that just made matter worse. The black border was present on all three refresh rate that my HDTV supports (25, 29 and 30Hz). System Restore came to my rescue.

So, I decided to write a little piece of software to reset the refresh rate. That, when combined with the MyPrograms plugin for MediaPortal, gives me a way of setting the HTPC back to 25Hz refresh rate via my remote control :)

So, here is how I did it…

Firstly I needed to use a few functions in user32.dll, so I created the following class…

    class User32
    {
        [DllImport("user32.dll")]
        public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);

        [DllImport("user32.dll")]
        public static extern int ChangeDisplaySettings(ref DEVMODE devMode, int flags);

        public const int ENUM_CURRENT_SETTINGS = -1;
    }

The User32 class needs the DEVMODE struct …

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct DEVMODE
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string dmDeviceName;

        public short dmSpecVersion;
        public short dmDriverVersion;
        public short dmSize;
        public short dmDriverExtra;
        public int dmFields;
        public int dmPositionX;
        public int dmPositionY;
        public int dmDisplayOrientation;
        public int dmDisplayFixedOutput;
        public short dmColor;
        public short dmDuplex;
        public short dmYResolution;
        public short dmTTOption;
        public short dmCollate;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string dmFormName;

        public short dmLogPixels;
        public short dmBitsPerPel;
        public int dmPelsWidth;
        public int dmPelsHeight;
        public int dmDisplayFlags;
        public int dmDisplayFrequency;
        public int dmICMMethod;
        public int dmICMIntent;
        public int dmMediaType;
        public int dmDitherType;
        public int dmReserved1;
        public int dmReserved2;
        public int dmPanningWidth;
        public int dmPanningHeight;

        public static DEVMODE Create()
        {
            DEVMODE dm = new DEVMODE();
            dm.dmDeviceName = new string(new char[32]);
            dm.dmFormName = new string(new char[32]);
            dm.dmSize = (short) Marshal.SizeOf(dm);
            return dm;
        }
    }

Since all I wanted to do was to reset the refresh rate, I just created a console application …

    static class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            int refreshRate;

            if (args.Length == 0 || !int.TryParse(args[0], out refreshRate))
            {
                refreshRate = 25;
            }

            bool silent = args.Length > 1 && args[1].ToLower() == "silent";

            string deviceName = Screen.PrimaryScreen.DeviceName;
            if (!silent)
            {
                Console.WriteLine("Device Name = " + deviceName);
                Console.WriteLine("Press [Enter] to proceed, or any other key to abort");
            }
            if (silent || Console.ReadKey().Key == ConsoleKey.Enter)
            {
                DEVMODE dm = DEVMODE.Create();
                User32.EnumDisplaySettings(Screen.PrimaryScreen.DeviceName, User32.ENUM_CURRENT_SETTINGS, ref dm);

                if (!silent)
                {
                    Console.WriteLine(string.Format("Press [Enter] to set refresh rate to {0}Hz, any other key to abort", refreshRate));
                }

                if (silent || Console.ReadKey().Key == ConsoleKey.Enter)
                {
                    dm.dmDisplayFrequency = refreshRate;
                    User32.ChangeDisplaySettings(ref dm, 0);
                }
            }
        }
    }

The primary screen name is fetched …

            string deviceName = Screen.PrimaryScreen.DeviceName;

The User32.EnumDisplaySettings is called in order to fill in the DEVMODE struct, as all I wanted to do was to change the refresh rate …

                DEVMODE dm = DEVMODE.Create();
                User32.EnumDisplaySettings(Screen.PrimaryScreen.DeviceName, User32.ENUM_CURRENT_SETTINGS, ref dm);

Next, I set the refresh rate to what I want and call User32.ChangeDisplaySettings …

                    dm.dmDisplayFrequency = refreshRate;
                    User32.ChangeDisplaySettings(ref dm, 0);

It works a treat in combination with the MyPrograms plugin for MediaPortal, with the command line of “25 silent”.

I found a very useful blog post which described how to do it.

Here is my take on it…

        function IsTimerEnabled()
        {
            var timer = $find("timer");
            return timer.get_enabled();
        }

        function PauseTimer()
        {
            var timer = $find("timer");
            timer.set_enabled(false);
            timer._stopTimer();
            window.status = "Timer paused";
            window.setTimeout("window.status = ''", 1000);
        }

        function ResumeTimer()
        {
            if (wasTimerEnabled)
            {
                var timer = $find("timer");
                timer.set_enabled(true);
                timer._startTimer();
                window.status = "Timer resumed";
                window.setTimeout("window.status = ''", 1000);
            }
        }

        var wasTimerEnabled = false;

        function OnOpenSomeDialog()
        {
            wasTimerEnabled = IsTimerEnabled();
            if (wasTimerEnabled)
            {
                PauseTimer();
            }
        }

        function OnSomeDialogClosed()
        {
            ResumeTimer();
        }

I recently had a requirement to allow a date to be updated from within a RadGrid, without any extra popups or such like.

So, I googled around and found this article.

However, it didn’t actually work as the telerik.getPreviousHtmlNode method didn’t exist, that may have been down to me using the Q2 2008 version of the controls and not the very latest version. I also found a problem with the dateSelected client-side event handler being called when I clicked on the pop-up toggle image for subsequent changes to dates other than the first one clicked on.

So, here is my solution. It’s a mix of jQuery, telerik jQuery extensions and plain old DOM manipulation.

C#

Main Page

This is all fairly standard stuff. I’m restricting the RadDatePicker to only allow dates of today onwards, I’m also setting up some string resources for use in my client-side javascript code and setting a javascript global variable to the ClientID of my single RadDatePicker.

protected void Page_Load(object sender, EventArgs e)
{
    ...

    RadDatePicker1.MinDate = DateTime.Today;

    ClientScript.RegisterClientScriptBlock(GetType(), "DatePickerID", "var datePickerClientID = '" + RadDatePicker1.ClientID + "';" + Environment.NewLine, true);

    Dictionary text = new Dictionary();
    text.Add("AjaxUpdating", Resources.Ajax_Updating);
    text.Add("AjaxUpdateSuccessful", Resources.Ajax_UpdateSuccessful);
    text.Add("AjaxUpdateFailed", Resources.Ajax_UpdateFailed);

    StringBuilder sb = new StringBuilder();
    sb.AppendLine("var text = new Array();");
    foreach (KeyValuePair textValue in text)
    {
        sb.AppendFormat("text['{0}'] = '{1}';{2}", textValue.Key, textValue.Value, Environment.NewLine);
    }
    ClientScript.RegisterClientScriptBlock(GetType(), "Strings", sb.ToString(), true);

    ...
}

Update Page

This is the page that is executed by the ajax call. Again, fairly simple stuff; Pull in the values from the Request.Form collection, act on them and prepare a response object which is formatted into a json string in order for the client-side code to be able to act on the results easily.

public partial class UpdateItemDate : System.Web.UI.Page
{
    [DataContract]
    private class ResponseObject
    {
        [DataMember]
        public bool Success { get; set; }

        [DataMember]
        public string ControlID { get; set; }

        [DataMember]
        public string ActualDate { get; set; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var response = new ResponseObject()
        {
            ControlID = Request.Form["ControlID"],
        };

        int itemID = 0;
        DateTime newDate = DateTime.MinValue;

        if (int.TryParse(Request.Form["ItemID"], out itemID) &&
            DateTime.TryParse(Request.Form["NewDate"], out newDate))
        {
            try
            {
                DataProvider dataProvider = ServiceLocator.Current.GetInstance();
                response.ActualDate = Request.Form["NewDate"];
                response.Success = dataProvider.SetDate(itemID, newDate);
                ServiceLocator.Current.GetInstance().SubmitChanges();
            }
            catch (Exception ex)
            {
                ServiceLocator.Current.GetInstance().Error
                (
                    ex,
                    string.Format("Cannot update date for item_id = {0}", itemID)
                );
                response.PromisedDate = Request.Form["OriginalDate"];
                response.Success = false;
            }
        }
        else
        {
            response.ActualDate = Request.Form["OriginalDate"];
            response.Success = false;
        }

        Response.Write(response.AsJsonDataContractString());
        Response.End();
    }
}

Javascript

I have two global variables defined here. The currentTextBox keeps track of which textbox the newly selected date should go in to, the calendarOpen flag tells me whether the calendar pop-up is visible. For some reason the telerik methods always returned “yes” when I asked them the question!

Because of the layout of my webpage (it being inside a pop-up RadWindow), I fixed the location of the calendar pop-up to 10,10. This was to avoid complications with the calendar dissappearing off the edge of my pop-up window. I believe that Telerik are still working on making the calendar part of the RadDatePicker not dissappear off-screen.

The calendarOpen flag is what I had to add in order to stop the dateSelected() method (called by the RadDatePicker client-side whenever a date is selected in the calendar pop-up) from clearing the currentTextBox under certain circumstances. I set this flag to “false” in the showPopup() method, this is called when the toggle img tag is clicked on. I’ve also wired in the “calendarOpening” client-side event with just one line of code to set the flag to “true”.

This way I know for sure when the calendar pop-up is actually visible. Without that code the currentTextBox was getting clear whenever I clicked on a toggle img tag other than the first one I clicked on after the initial page load. Very odd behaviour, but this work-around seems to work nicely :)

The UpdateItemDate() method just sets the text of the currentTextBox to inform the user that something is happening. It then makes the ajax call, passing the ItemID, NewDate, OriginalDate and ControlID to the server-side. I’m using a callback here so that my “resetting” of the currentTextBox text only happens once an update has been performed. I have also specified “json” as the final parameter, this has the effect of automatically parsing the server response into an object and passing it to my callback method.

The UpdateItemDateCallback() method, takes two parameters. The second one isn’t actually used, according to what I’ve read this can only ever be “Success” anyway. See here for more details. I find the textBox control using jQuery, currentTextBox may not be correct anymore. I then set the text and colour accordingly. Finally, I set up a two second timer to put the text to what it should be, ie – data.ActualDate.

var currentTextBox = null;
var calendarOpen = false;

function showPopup(e)
{
    calendarOpen = false;
    currentTextBox = e.srcElement.parentNode.firstChild;
    var datePicker = $find(datePickerClientID);
    datePicker.set_selectedDate(datePicker.get_dateInput().parseDate(currentTextBox.innerText));
    datePicker.showPopup(10, 10);
}

function dateSelected(sender, args)
{
    if (calendarOpen && currentTextBox != null)
    {
        var itemID = currentTextBox.parentNode.lastChild.previousSibling.innerText;
        var originalDate = currentTextBox.innerText;
        currentTextBox.innerText = args.get_newValue() + " ";
        UpdateItemDate(itemID, args.get_newValue(), originalDate);
    }
}

function calendarOpening(sender, args)
{
    calendarOpen = true;
}

function UpdateItemDate(itemID, newDate, originalDate)
{
    currentTextBox.innerText = text["AjaxUpdating"];
    $.post("UpdateItemDate.aspx", { ItemID: itemID, NewDate: newDate, OriginalDate: originalDate, ControlID: currentTextBox.id }, UpdateItemDateCallback, "json");
}

function UpdateItemDateCallback(data, textStatus)
{
    textBox = $("#" + data.ControlID);
    var str = data.Success ? "AjaxUpdateSuccessful" : "AjaxUpdateFailed";
    var colour = data.Success ? "Blue" : "Red";
    textBox.text(text[str]).css("color", colour);
    window.setTimeout("$('#" + data.ControlID + "').text('" + data.ActualDate + "').css('color', '');", 2000);
}

HTML

This should all be fairly self-explanatory, the RadScriptManager is in there so we get the $find method and $telerik object to play with. Note the extra (hidden) <asp:Label /> tag, which is used to store my item_id.

<body>
    ...
    <form id="form1" runat="server">
        ...
        <telerik:RadScriptManager ID="RadScriptManager1" runat="server">
            <Scripts>
                <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js" />
            </Scripts>
        </telerik:RadScriptManager>
        <telerik:RadDatePicker ID="RadDatePicker1" runat="server" style="display:none;" DateInput-DateFormat="d MMM yyyy">
            <ClientEvents OnDateSelected="dateSelected" OnPopupOpening="calendarOpening" />
        </telerik:RadDatePicker>
        <radG:RadGrid ID="myGrid" runat="server">
            <MasterTableView>
                <Columns>
                    ...
                    <radG:GridTemplateColumn>
                        <HeaderTemplate>
                            <asp:Literal ID="myDateHeading" runat="server" Text='<%# Resources.myDateHeading %>'></asp:Literal>
                        </HeaderTemplate>
                        <ItemTemplate>
                            <div class="myDate">
                                <asp:Label ID="myDate" runat="server" Text='<%# Eval("my_date", "{0:d MMM yyyy}") %>' />
                                <asp:Image ID="popupImage" runat="server" ImageUrl="~/images/datePickerPopup.gif" onclick='showPopup(event)' />
                                <asp:Label ID="itemId" runat="server" CssClass="itemId"><%# Eval("item_id") %></asp:Label>
                            </div>
                        </ItemTemplate>
                    </radG:GridTemplateColumn>
                ...
                </Columns>
            </MasterTableView>
        </radG:RadGrid>
        ...
    </form>
    ...
</body>

CSS

And finally a little bit of CSS to make it look nice!

.myDate
{
    white-space: nowrap;
    display: inline;
    position: relative;
    width: 100%;
}

.myDate span
{
    margin-right: 30px;
}

.myDate img
{
    float: right;
    margin-top: -3ex;
}

.myDate .itemId
{
    display: none;
}

Well, I hope that helps someone out, as well as serving as a reminder for me in the future should such a requirement arise again!

In case you’re wondering I’ve used the google prettyprint css/js to format my code.

My computer installation isn’t what you could call typical. I have a home made 19″ rack in my loft where I keep a bunch of stuff (including my router, network switches & patch panel, server PC, router and my main PC).

Up until now my “power switch” for the main PC has come in the form of setting up a wake on lan user on my router and logging on to that page using my PSP. That has worked great except for the times when the PC plays up and I need to press the reset or power button directly. When the needs arises for that I have to climb up in to the loft to get to the PC.

So, last week I did a little experiment with an old momentary PC switch and a length of CAT5 cable. I wired up the CAT5 cable straight through (ie – not to any standards). I made two “patch cables”, one for the PC end and one for the PC end. I just used one of the 4 pairs and basically spliced it into the middle of my spare momentary switch. Since I already had a spare RJ45 socket in my study I just plugged the switch end into that, and plugged the connector end into my patch panel for that socket. I then plugged the connector into a spare PC’s motherboard.

I climbed back down my loft ladders and pressed the button, climbed back up into the loft and hey presto the PC was booting up. My experiment was a success; I could use my existing CAT5 wiring to control my PC.

So, I purchased a few bits’n'bobs from farnell and another shop called the mod blog and made myself a little switch box with power and reset buttons on it. Oddly enough, my PC locked up during boot up this morning, so I had to use the reset button. It worked perfectly.

The wiring in the PC isn’t great as I’m not the worlds best solderer, but it works and because I bought the right bits, I didn’t actually need to splice into anything in the PC. The wiring sits between the normal power and reset switches in the case and the motherboard. So, I can power on/off and reset either from my little box in the study or from in the loft directly on the PC.

Parts List

Description Code Cost Supplier
Project Box 301-322 £2.15 www.farnell.co.uk
Red Switch 163-4627 £1.23 www.farnell.co.uk
Green Switch 163-4632 £1.23 www.farnell.co.uk
Cable Gland 117-8960 £1.86 www.farnell.co.uk
4 pin fan header CONF-4HWhite £0.40 www.themodblog.co.uk
10 Way Rainbox IDE Ribbon Calbe RID-10R £0.40 www.themodblog.co.uk
2 Way PC Header Connector (with Crimp Pins) CONKK-02 £1.26 www.themodblog.co.uk
Total £8.53

So, the next project is to do it again for another computer!

Components

The components, 2 switches, cable gland and box

Cable Gland

The back of the finished box

The finished box

The finished item