views:

1187

answers:

4

Hi, i am trying to stream video over http to iphone without a streming server with .net. After some tests i found that if you just upload iphone compatible video to your server, iis7 works just fine and iphone startsplaying video after small buffer time and continues to download in the background.

My problem is, i am unable to do it with .net. I have tried with

    public static void SmallFile(string filename, string filepath, string contentType)
{
    try
    {
        FileStream MyFileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
        long FileSize;
        FileSize = MyFileStream.Length;
        byte[] Buffer = new byte[(int)FileSize];
        MyFileStream.Read(Buffer, 0, (int)MyFileStream.Length);
        MyFileStream.Close();
        HttpContext.Current.Response.ContentType = contentType;
        HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
        HttpContext.Current.Response.BinaryWrite(Buffer);

    }
    catch
    {
        HttpContext.Current.Response.ContentType = "text/html";
        HttpContext.Current.Response.Write("Downloading Error! " + filename + " not found!");
    }
    HttpContext.Current.Response.End();
}

or with

public static void ResumableFile(string filename, string fullpath, string contentType)
{
    try
    {
        FileStream myFile = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        BinaryReader br = new BinaryReader(myFile);
        try
        {
            HttpContext.Current.Response.AddHeader("Accept-Ranges", "bytes");
            HttpContext.Current.Response.Buffer = false;
            long fileLength = myFile.Length;
            long startBytes = 0;

            //int pack = 10240; //10K bytes
            int pack = 1048576; //1024K bytes
            if (HttpContext.Current.Request.Headers["Range"] != null)
            {
                HttpContext.Current.Response.StatusCode = 206;
                string[] range = HttpContext.Current.Request.Headers["Range"].Split(new char[] { '=', '-' });
                startBytes = Convert.ToInt64(range[1]);
            }
            HttpContext.Current.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
            if (startBytes != 0)
            {
                HttpContext.Current.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
            }
            HttpContext.Current.Response.AddHeader("Connection", "Keep-Alive");
            HttpContext.Current.Response.ContentType = contentType;
            HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));

            br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
            int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1;

            for (int i = 0; i < maxCount; i++)
            {
                if (HttpContext.Current.Response.IsClientConnected)
                {
                    HttpContext.Current.Response.BinaryWrite(br.ReadBytes(pack));
                    }
                else
                {
                    i = maxCount;
                }
            }
        }
        catch
        {
            HttpContext.Current.Response.ContentType = "text/html";
            HttpContext.Current.Response.Write("Downloading Error! " + filename + " not found!");
        }
        finally
        {
            br.Close();
            myFile.Close();
        }
    }
    catch
    {
        HttpContext.Current.Response.ContentType = "text/html";
        HttpContext.Current.Response.Write("Downloading Error!" + filename + " not found!");
    }
}

In both, i get error saying server is not configured properly. I then removed

 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));

part so it won't trigger full download but result was the same.

I have checked responses from server and there is no different/extra header coming from server when i directly download file.

What i am trying to findout what would be enabling iphone to buffer and start playing video when i directly download video file and how can i implemnet it with .net

If youwonder why i just don't use iis, i need to put some sort of leech protecttion due to bandwidth restrictions

Anyone have any exprience?

UPDATE

Here is the first request and response from iis

GET /test.mp4 HTTP/1.1
Host: 192.168.2.200
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; tr-tr) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16
Cache-Control: max-age=0
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: tr-tr
Accept-Encoding: gzip, deflate
Connection: keep-alive


HTTP/1.1 200 OK
Content-Type: video/mp4
Last-Modified: Wed, 23 Dec 2009 20:12:57 GMT
Accept-Ranges: bytes
ETag: "e6ad9151c84ca1:0"
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Wed, 23 Dec 2009 21:07:19 GMT
Content-Length: 2301438

And second request and response

GET /test.mp4 HTTP/1.1
Host: 192.168.2.200
Range: bytes=0-2269183
Connection: close
User-Agent: Apple iPhone OS v3.1.2 CoreMedia v1.0.0.7D11
Accept: */*
Accept-Encoding: identity



HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Last-Modified: Wed, 23 Dec 2009 20:12:57 GMT
Accept-Ranges: bytes
ETag: "e6ad9151c84ca1:0"
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Wed, 23 Dec 2009 21:11:33 GMT
Connection: close
Content-Length: 2269184
Content-Range: bytes 0-2269183/2301438

As i understand iphone requests different bytes on second request and so on. Is there anyway getting c# to send those bytes range to the client?

+1  A: 

I'd perform some sort of message sniffing.

Basically, I'd set up something that you can stream video to iPhone with (like TVersity) and then set up something to intercept the traffic between TVersity and the iPhone so that you can inspect the HTTP request and response.

Here is a blog post on how to set up TVersity:

http://geeks.pirillo.com/profiles/blogs/2300301:BlogPost:38497

The relative url "/iPhone" is the one that you want to sniff traffic on. It should shed some light on the proper message exchange pattern to download video to the iPhone.

casperOne
please see my update
nLL
+2  A: 

I think i've found my solution at http://dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx

nLL
A: 

Can you send me the sourcecode for this? I am trying to do a similar thing with iPhones and Android devices.

shadowpyro
A: 

try this one http://code.google.com/p/talifun-web/wiki/StaticFileHandler

or link in my first reply has source code

nLL