Over the last few weeks I have been working on an ASP.NET WebAPI that was designed to stream video from one of the company servers and play it on an HTML5 <video> element. Following a guide on C# Corner, we got the API published and now when the link for one of our videos is pasted into a browser, it starts to download (which, by the way, I'm not sure if it's supposed to do that when all we're trying to do is stream).
The files we need to stream are mp4 and are going to be used largely on iOS devices through Safari. And before anyone asks: srcVid is programmed and confirmed to be able to encode .mp4 files successfully, as we have managed to hard-code videos into this element with no issue. With that said, this is how the page handles its HTML5 elements:
<video autoplay muted id="trainVid" style="width: 75%; height: auto;" controls>
<source id="srcVid" runat="server"
type='video/mp4; codecs*="avc1.424085, mp4a.40.2"' />
</video>
On the API side, here are how the videos are processed, largely following the example set by the C# article, as well as some help from a Stephen Cleary article:
public class VidService
{
public async void WriteVidBytes(Stream outputStream,
HttpContent content, TransportContext tc)
{
try
{
var filePath = "\\\\server\\link\\to\\file.mp4";
int bufferSize = 1000;
byte[] buffer = new byte[bufferSize];
using (var fileStream = new FileStream(
filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
int fileSize = (int)fileStream.Length;
while (fileSize > 0)
{
int cnt = fileSize > bufferSize ? bufferSize : fileSize,
readBufferSize = fileStream.Read(buffer, 0, cnt);
await outputStream.WriteAsync(buffer, 0, readBufferSize);
fileSize -= readBufferSize;
}
}
}
catch (HttpException ex) { return; }
finally { outputStream.Close(); }
}
public HttpResponseMessage GetVidContent()
{
// NOTE: please see the Edit on 6/10
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new PushStreamContent(
(Action<Stream, HttpContent, TransportContext>)WriteVidBytes
)
};
return httpResponse;
}
}
public class VidController : ApiController
{
private static readonly VidService vs = new VidService();
[HttpGet]
public HttpResponseMessage GetVid(int id)
{
return vs.GetVidContent(id);
}
}
*Note that the actual program dynamically fetches video links through a Video.cs object
And finally on the C# side:
protected void LoadVideo(int vidId)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
string.Format("http://mobileAPI.website.com/Vid/GetVid/" + vidId.ToString()));
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
string jsonString;
using (Stream stream = resp.GetResponseStream())
{
StreamReader r = new StreamReader(stream, System.Text.Encoding.UTF8);
jsonString = r.ReadToEnd();
}
srcVid.Src = jsonString;
}
When opening the page, LoadVideo() seems to execute with no errors -- but after this, the page goes blank and hangs forever. I'm thinking this may be because I'm putting the wrong value into srcVid.Src, but if I don't put in the jsonString, then what do I put in for the source?
As always, any help would be greatly appreciated! If I missed anything obvious, please let me know, as this is the first time I have worked with WebAPI.
UPDATE 1 (6/10)
I made a secondary method that took WriteVidBytes and turned it into a Task -- and other than turning it into a Task, the code inside is exactly the same. Another difference, also, is how GetVidContent fetches the data:
public HttpResponseMessage GetVidContent(int vId)
{
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new PushStreamContent(async
(outputStream, httpContext, transportContext) =>
{
await WriteVidTask(outputStream, httpContext, transportContext);
}),
};
return httpResponse;
}
However, the page still hangs even though there is no problem getting the file through Postman or Fiddler.