Monthly Archives: November 2010

Media Streaming MVC and Preconditions

I’ve added more HTTP precondition support to my Media Streaming / Resuming Downloads project for MVC on CodePlex. In the last version I added a quick bit of code to enable returning a Not Modified (304) status code if a request came in with If-Modified-Since precondition. Today I’ve committed source changes which now support 4 other preconditions: If-Unmodified-Since, If-Range, If-Match and If-None-Match.

So far the only client I have that issues a request other than If-Modified-Since was Firefox. It used the If-Range request once but I can’t replicate it. I would rather not implement my own client to test these request types as I’ve already got a preconceived notion on how it should work and I’m more interested in testing real products that have implemented the protocols according to their understanding.

Continue reading

Advertisements

Media Streaming MVC is now Time Aware!

I was looking at my CodePlex Project to see if I could ease debugging a bit by logging the request and response headers. Before I got into the meat of things I enabled the Trace attribute in the web.config of my test project. This gave me the request headers but not the response. Before I had a chance to really dig more into this, I noticed my iPad was sending If-Modified-Since HTTP header in its request for a media file.

I thought about this for a minute and realized that in some cases I’m aware of the LastModified time for a media file and I should be able to compare the two. I started hacking at the project to get initial support to see how it would work. I ran into a couple things:

Not all timestamps are created equal.

The date and time my iPad sends with the request is GMT. The DateTime on my media file was localized (GMT -5:00). I decided it should be very quick to just convert them both to UTC and compare them. I wrote the code to parse the request headers, pass through the new Precondition in the ResumambleDownloadRequest object, and compare them in the ResumableDownloadResult base class. Unfortunately the comparison always thought the file had been modified more recently than the request and despite re-streaming the file, subsequent requests still contained the same If-Modified-Since timestamp.

Continue reading

My First CodePlex Project: MVC Resumable Downloads

My first CodePlex Project is an attempt to bring iOS streaming and resuming downloads to ASP.NET MVC.

In my previous post I discussed how I’d hacked together a quick solution to bring resuming download capability to dynamic MVC content. Though I got some credit on StackOverflow for coming up with that solution I wasn’t terribly happy with how patched together it was and how little support it had for the fully HTTP protocol specification for Content-Range requests.

I mulled it over for awhile and did some searching and finally came up with more information about the specification, applications that use it and examples of how to solve the problem for static files. The best solution I found was an adaptation of a conversion. Rather than further tweaking the solution and trying to force it to fit in the context of an ASP.NET MVC application framework I decided to do a clean implementation using the framework features.

I thought my initial instinct about the design was correct: use an ActionFilter to examine the request headers for a partial data request and a custom Result to output the data and necessary headers. I kept this structure but expanded on how I parsed the ranges and output different results based on the request. The new design would remove almost all of the effort required for a developer to implement the solution.

In the end the new solution took a little over a day to implement and get working with an iPad streaming a video. After a few more hours of tweaking I think I arrived at a better and cleaner solution that should be easily extensible without requiring any modification in order to be useful for common scenarios. It was also more dynamic and more capable than the original solution by adding support for multiple ranges in a single request and adjusted the output result to suit the request without requiring higher-level intervention.

I think it’s a pretty good solution and it could be helpful to someone. I would like to see it extended and become even more useful. The only way I could realistically see this happening is to make the source publicly available and see how it matures. So with that in mind, I took the plunge and I now have my first CodePlex project.

Please be kind. This is my first project. I look forward to see how it’s received and whether other people find it useful!

-Erik

iOS Media Streaming for ASP.NET MVC

UPDATE (6/27/2011): Taking some lessons learned from the project below, I’ve started another simplified project. Take a look, it probably suits the needs more effectively.

I ran across a question on StackOverflow from a developer asking how to get the correct response headers to stream media to iOS devices (iPhone, iPad, etc.) from ASP.NET MVC 2. I had a few quick ideas but they weren’t really gaining traction so I fired up Visual Studio and tried things out.

First I knew I was going to need to make my Action react to requests for byte ranges. This is key to getting iOS devices to stream media. My first thought was to make an ActionFilter to read the request headers and pass the values on to my Action.

public class ByteRangeRequest : FilterAttribute, IActionFilter
{
    protected string RangeStart { get; set; }
    protected string RangeEnd { get; set; }

    public ByteRangeRequest(string RangeStartParameter,
                            string RangeEndParameter)
    {
        RangeStart = RangeStartParameter;
        RangeEnd = RangeEndParameter;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        if (!filterContext.ActionParameters.ContainsKey(RangeStart))
            filterContext.ActionParameters.Add(RangeStart, null);
        if (!filterContext.ActionParameters.ContainsKey(RangeEnd))
            filterContext.ActionParameters.Add(RangeEnd, null);

        var request = filterContext.RequestContext.HttpContext.Request;
        var headerKeys = request.Headers.AllKeys.Where(key =>
            key.Equals("Range", StringComparison.InvariantCultureIgnoreCase));
        Regex rangeParser = new Regex(@"(\d+)-(\d+)", RegexOptions.Compiled);

        foreach (string headerKey in headerKeys)
        {
            string value = request.Headers[headerKey];
            if (!string.IsNullOrEmpty(value))
            {
                if (rangeParser.IsMatch(value))
                {
                    Match match = rangeParser.Match(value);

                    filterContext.ActionParameters[RangeStart] =
                        int.Parse(match.Groups[1].ToString());
                    filterContext.ActionParameters[RangeEnd] =
                        int.Parse(match.Groups[2].ToString());
                    break;
                }
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }
}

I decided to specify the parameter names you want back just for flexibility. I could have chosen obscure names that were unlikely to collide or maybe stick the values in the TempData but I liked this approach better. It seems more concrete and obvious to me. And with these parameters, you could be passing on just the relevant segment of the stream to the output result but I was in a hurry and this was the smallest I could make my code.

With the request headers parsed I needed a way to return the subset of bytes from my media with the proper response headers. It turns out this was easier than I’d expected but not easier than I made it. After many iterations to get it working and a few more removing all the pieces it turned out where unnecessary I ended up with FileStreamRangeResult based on FileStreamResult. Using this as a guide, the other FileResult types could easily be made to work the same way.

public class FileStreamRangeResult : FileStreamResult
{
    public int StartIndex { get; set; }
    public int EndIndex { get; set; }
    public long TotalSize { get; set; }

    public FileStreamRangeResult(int startIndex, int endIndex,
        long totalSize, string contentType, Stream fileStream)
        : base(fileStream, contentType)
    {
        StartIndex = startIndex;
        EndIndex = endIndex;
        TotalSize = totalSize;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = this.ContentType;
        response.AddHeader(
            HttpWorkerRequest.GetKnownResponseHeaderName(
                HttpWorkerRequest.HeaderContentRange),
            string.Format("bytes {0}-{1}/{2}",
                StartIndex, EndIndex, TotalSize));
        response.StatusCode = 206;

        WriteFile(response);
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        Stream outputStream = response.OutputStream;
        using (this.FileStream)
        {
            byte[] buffer = new byte[0x1000];
            int totalToSend = EndIndex - StartIndex;
            int bytesRemaining = totalToSend;
            int count = 0;

            FileStream.Seek(StartIndex, SeekOrigin.Begin);

            while (bytesRemaining > 0)
            {
                if (bytesRemaining <= buffer.Length)
                    count = FileStream.Read(buffer, 0, bytesRemaining);
                else
                    count = FileStream.Read(buffer, 0, buffer.Length);

                outputStream.Write(buffer, 0, count);
                bytesRemaining -= count;
            }
        }
    }
}

With those done all that’s left is to grab a properly formatted video and build my action.

[ByteRangeRequest("StartByte", "EndByte")]
public FileStreamResult StreamContent(int? StartByte, int? EndByte)
{
    string fileName = @"C:\temp\99RedBalloons.mp4";
    FileInfo mediaFile = new FileInfo(fileName);

    FileStream contentFileStream = mediaFile.OpenRead();
    var time = mediaFile.LastWriteTimeUtc;

    if (StartByte.HasValue && EndByte.HasValue)
        return new FileStreamRangeResult(StartByte.Value,
            EndByte.Value, contentFileStream.Length,
            "video/x-m4v", contentFileStream);

    return new FileStreamRangeResult(0,
        (int)contentFileStream.Length-1, contentFileStream.Length,
        "video/x-m4v", contentFileStream);
}

This was a productive night for me. I forgot dinner and missed my workout but now I know I can stream media to all my gadgets from my MVC projects! Keep in mind this was just a proof of concept so don’t be too hard on the rough edges!

-Erik

P.S. – It took me a lot of effort to get that working. If you feel like being kind, please go upvote my answer!

Using SyncRoot for Multithreaded Applications

I previously wrote an update to a post I’d written about adding extension methods to the .NET Framework 3.5 to provide simple multithreading capability in an application. In the update I extended my solution from managing the starting of threads from the Managed Thread Pool and blocking the main thread until they all complete to also collect return data from these threads.

To accomplish this I had instantiated a List<T> object before starting my threads. Since I knew the number of threads I was going to start and since they would all return the same type of data, I gave the list an initial capacity so it wouldn’t need to grow. Since the object was instantiated before starting the threads, the child threads have access to the object and can add their results.

To ensure there were no collisions during the write operations from the various threads, I added my own synchronous ThreadSafeAdd extension method. The method was very simple, grab the list object’s SyncRoot property and use a lock on it while I called the add method.

public static void ThreadsafeAdd<T>(this List<T> list, T value)
{
    object spinLock = ((ICollection)list).SyncRoot;

    lock (spinLock)
    {
        list.Add(value);
    }
}

Why was this necessary?

In multithreaded programming you can never be sure what thread will be writing to a shared object at a given time. More problematic is the fact that threads can be preempted at (almost) any point in its execution while another thread does some work. So say I didn’t give the list an initial capacity and let it grow as needed. Memory isn’t added to the existing allocation for the list when it needs to expand. Instead a new block of memory is allocated, the existing contents copied to the new memory location, the object is reassigned to the new memory space and the old space is (eventually) collected for re-use.

Imagine what happens when one thread attempts to add an item to a list that has reached capacity. The steps above start to be executed but before they can complete the working thread is interrupted and another thread is resumed. Assume that thread wants to access the same object. The reference to that object still points to the full memory location so the process outlined above is started again with this thread. When each of these threads completes they will have copies of the old data in their new memory locations to which each of them adds their item before updating the reference and terminating. The list reference can only point to one location so whoever updates it last wins. Because of this, the other thread’s result which was only added to their new memory allocation, is lost.

To prevent this from happening we have a number of options at our disposal. For my purposes I went with a lightweight lock object. This works really well in a situation where you don’t expect your lock to last a long time which is exactly what we need. The first thread that gets to the lock statement gets exclusive access to the statements in the code block. No other thread can execute that code block on that instance of an object until the thread that has the lock completes. This methodology can only succeed if everyone uses the same object for locking.

The list inherits from ICollection which requires implementers to expose a gettable object named SyncRoot. From MSDN: “An object that can be used to synchronize access to the ICollection.” If you reflect the List<T> object you can see the implementation. Needless to say, there is work done to ensure an instance object has a single, non changing SyncRoot object on which we can lock.

Using an object exposed by the instance is better than using your own. Though you may control all the code which requires synchronization it’s still conceptually cleaner to lock on a property of an object than your own. Since this property is available, it should be standard practice to use it. If everyone does it correctly, then objects that become shared at a higher level can continue to ensure they are locking on the same object and therefore not stepping on each others’ toes. If everyone used their own lock object, none of the disparate code pieces would be locking on the same object and threads could still collide.

After I wrote all this stuff I decided to see if I was on target with what the new synchronous objects in 4 are using. Since my project is restricted to .NET 3.5 I can’t make use of these objects but I can take a peek and see if I’m doing it right. Taking a quick peek at .NET 4’s SynchronousList.Add(…) I see:

internal class SynchronizedList : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable
{
    // Fields
    private List<T> _list;
    private object _root;

    // Methods
    internal SynchronizedList(List<T> list)
    {
        this._list = list;
        this._root = ((ICollection) list).SyncRoot;
    }

    public void Add(T item)
    {
        lock (this._root)
        {
            this._list.Add(item);
        }
    }
    ...
}

SynchronousList is assigning the SyncRoot property to _root and locks the same way as I’ve done in the code snippet above.

There are other places where SyncRoot may be exposed. If you find yourself wanting to synchronize access to an object, take a look at its properties and see if something is already available. It’ll be safer and faster than defining your own.

lock(Signature.SyncRoot) {
   Signature.Text = "-Erik";
}

NuPack is now NuGet

I wrote a post talking about a CodePlex project called NuPack. They held a vote to change the name and the winner was NuGet (pronounced “New Get”). The old CodePlex URL redirects to the new name for now but you should probably update the bookmarks I’m sure you all made.

I think it’s a great project and a big help to both developers looking to add functionality to their programs or speed development as well as the open communities working hard to get exposure and bring useful tools to developers.

Ruler of Omicron Persei 8,
-Erik