The problem is this:
To implement this task, I took as a basis for the article:
http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/
It worked. To give the stream a video file independently and in parallel.
I was looking on.
Next it was necessary to solve the problem of broadcasting to multiple customers (paragraph 3 in the job). I took this article: http://gigi.nullneuron.net/gigilabs/streaming-data-with-asp-net-web-api-and-pushcontentstream/
Since I have to give evidence in the video byte - I replaced the StreamWriter class to Stream.
It works for one of the first client.
I made a website Asp.Net WebForms + WebApi + HTML5.
Web page - to run a video manager and viewed by users.
WebApi gives the player for <video>
(HTML5) video stream.
HTML5:
<video>
<source src="http://localhost:8080/SiteVideoStreaming/api/live/?filename=nameFile" />
</video>
WebApi controllers:
//Controllers
public class LiveController : ApiController
{
private static ConcurrentBag<Stream> clients; // List of clients who need to simultaneously deliver video data
static string fileName = "";
static LiveController()
{
clients = new ConcurrentBag<Stream>();
WriteToStream(); // The first call - start to play a video file
}
[HttpGet]
public HttpResponseMessage Subscribe(string filename)
{
fileName = HostingEnvironment.MapPath("~/Videos/") + filename;
var response = Request.CreateResponse();
response.Content = new PushStreamContent((a, b, c) => { OnStreamAvailable(a, b, c); }, "video/mp4");
return response;
}
private void OnStreamAvailable(Stream stream, HttpContent content, TransportContext context)
{
clients.Add(stream); // Add new client
}
//Class record a video file into a streams
public async static void WriteToStream()
{
var buffer = new byte[65536];
using (var video = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
foreach (var client in clients)// Each client in turn we return video data
{
try
{
await client.WriteAsync(buffer, 0, bytesRead); // ERROR - here !!! when you connect a second client
await client.FlushAsync();
}
catch (Exception ex)
{
Stream ignore;
clients.TryTake(out ignore);
}
}
length -= bytesRead;
}
}
}
}
If the request first came from one client - is given to video. Working. If the request from the second client - when you try to start to give him a stream error occurs. In this connection drops and the first client.
The error is as follows:
[System.Web.HttpException] = {"The remote host closed the connection. The error code is 0x800704CD."}
As I understood after a search on the Internet is:
0x800704CD "An operation was attempted on a nonexistent network connection."
Tell me that I'm not doing right? Thank you.
I do so. I use this controller:
public class VideoController : ApiController
{
// GET api/<controller>
public HttpResponseMessage Get(string filename)
{
if (filename == null)
return new HttpResponseMessage(HttpStatusCode.BadRequest);
string filePath = HostingEnvironment.MapPath("~/Videos/") + filename;
if (Request.Headers.Range != null)
{
//Range Specifc request: Stream video on wanted range.
try
{
//NOTE: ETag calculation only with file name is one approach (Not the best one though - GUIDs or DateTime is may required in live applications.).
Encoder stringEncoder = Encoding.UTF8.GetEncoder();
byte[] stringBytes = new byte[stringEncoder.GetByteCount(filePath.ToCharArray(), 0, filePath.Length, true)];
stringEncoder.GetBytes(filePath.ToCharArray(), 0, filePath.Length, stringBytes, 0, true);
MD5CryptoServiceProvider MD5Enc = new MD5CryptoServiceProvider();
string hash = BitConverter.ToString(MD5Enc.ComputeHash(stringBytes)).Replace("-", string.Empty);
HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
partialResponse.Headers.AcceptRanges.Add("bytes");
partialResponse.Headers.ETag = new EntityTagHeaderValue("\"" + hash + "\"");
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, new MediaTypeHeaderValue("video/mp4"));
return partialResponse;
}
catch (Exception ex)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
else
{
return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
}
}
}
On the client side - I run it <video>
video player through technology SignalR.
User contributions licensed under CC BY-SA 3.0