Как сделать частично загруженную страницу при стриминге видео?
От: Sharov Россия  
Дата: 07.11.23 20:25
Оценка:
Здравствуйте.

Дан сл. код:
 [HttpGet(Name = "streamer")]
        public async Task<IActionResult> Get123()
        {
            using (var tcpClient = new TcpClient())
            {
                await tcpClient.ConnectAsync("localhost", 5555);
                using (var netStream = tcpClient.GetStream())
                {
                    Response.ContentType = "multipart/x-mixed-replace; boundary=abcd";
                    await netStream.CopyToAsync(Response.Body);
                }
            }

            return Ok();
        }


  Клиент
 
<html style="height: 100%;">
  <head>
     <meta name="viewport" content="width=device-width, minimum-scale=0.1">
  </head>
  <body style="margin: 0px; height: 100%; background-color: rgb(14, 14, 14);">
    <img style="display: block;-webkit-user-select: none;margin: auto;background-color: hsl(0, 0%, 25%);" src="http://localhost:5030/Streamer" width="219" height="184">
  </body>
</html>

Суть кода такова -- при запросе браузера перегоняю поток jpeg'ов , по сути mjpeg, для отображения видео.
Все работает, но есть вопрос-проблема -- как сделать так, чтобы страница при сеансе все время была в загрузке,
а не просто загрузилась и все? Ну т.е. крестик бы был (например, в хроме), чтобы при его нажатии остановить
поток видео на сервере? Потому как сейчас запрос находится на строке
await netStream.CopyToAsync(Response.Body);

и страница полностью загружена. А хотелось бы иметь возможность при нажатии на крестик в браузере поток остановить, ибо
по сути каждый запрос это утечка ресурсов -- клиент закрыл страницу, а я об этом ничего не знаю и продолжаю куда-то гнать
данные. (Кстати, я закрыл страницу , что при этом будет с Response.Body?)

Т.е. как сделать так, чтобы на время стриминга страница полностью не загружалась?

Заранее благодарю.
Кодом людям нужно помогать!
Re: Как сделать частично загруженную страницу при стриминге видео?
От: Разраб  
Дата: 08.11.23 00:03
Оценка:
Здравствуйте, Sharov, Вы писали:


S>Т.е. как сделать так, чтобы на время стриминга страница полностью не загружалась?

https://developer.mozilla.org/en-US/docs/Web/API/Document

может быть надо все время генерить dom документа, не давая завершиться readyState?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Как сделать частично загруженную страницу при стриминге
От: vsb Казахстан  
Дата: 08.11.23 00:30
Оценка: +2
Здравствуйте, Sharov, Вы писали:

Ты хочешь чего-то очень странного. Никто не останавливает видео крестиком. Для остановки видео используется кнопка в интерфейсе плеера. Если твой http сервер поддерживает range запросы, то браузер, по крайней мере с обычными форматами видео, не будет загружать всё. Если не хочешь полагаться на браузер — напиши свой плеер, как в ютубе, который грузит чанки сам.

S>и страница полностью загружена. А хотелось бы иметь возможность при нажатии на крестик в браузере поток остановить, ибо

S>по сути каждый запрос это утечка ресурсов -- клиент закрыл страницу, а я об этом ничего не знаю и продолжаю куда-то гнать
S>данные. (Кстати, я закрыл страницу , что при этом будет с Response.Body?)

Когда клиент закроет страницу — у тебя сокет с той стороны закроется и твой сервер про это почти сразу же узнает. Как это .NET обрабатывает, я не знаю, но могу предположить, что он при попытке записи в закрытый сокет выкинет исключение. "В никуда" писать — это надо постараться.
Отредактировано 08.11.2023 0:32 vsb . Предыдущая версия .
Re[2]: Как сделать частично загруженную страницу при стриминге
От: Sharov Россия  
Дата: 08.11.23 07:16
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Ты хочешь чего-то очень странного. Никто не останавливает видео крестиком. Для остановки видео используется кнопка в интерфейсе плеера. Если твой http сервер поддерживает range запросы, то браузер, по крайней мере с обычными форматами видео, не будет загружать всё. Если не хочешь полагаться на браузер — напиши свой плеер, как в ютубе, который грузит чанки сам.


Неудачная аналогия, согласен. Нужно, чтобы во время показа видео страница была "в загрузке", а не "загрузилась".

vsb>Когда клиент закроет страницу — у тебя сокет с той стороны закроется и твой сервер про это почти сразу же узнает. Как это .NET обрабатывает, я не знаю, но могу предположить, что он при попытке записи в закрытый сокет выкинет исключение. "В никуда" писать — это надо постараться.


Ну вот со стороны web api хотелось бы знать соотв. события.
Кодом людям нужно помогать!
Re[3]: Как сделать частично загруженную страницу при стриминге
От: rameel https://github.com/rsdn/CodeJam
Дата: 08.11.23 12:19
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Ну вот со стороны web api хотелось бы знать соотв. события.


Добавь в метод параметр CancellationToken
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: Как сделать частично загруженную страницу при стримин
От: vsb Казахстан  
Дата: 08.11.23 12:23
Оценка:
Здравствуйте, Sharov, Вы писали:

vsb>>Ты хочешь чего-то очень странного. Никто не останавливает видео крестиком. Для остановки видео используется кнопка в интерфейсе плеера. Если твой http сервер поддерживает range запросы, то браузер, по крайней мере с обычными форматами видео, не будет загружать всё. Если не хочешь полагаться на браузер — напиши свой плеер, как в ютубе, который грузит чанки сам.


S>Неудачная аналогия, согласен. Нужно, чтобы во время показа видео страница была "в загрузке", а не "загрузилась".


Прямого API для этого я не знаю. В целом страница "загружается", пока либо основной HTML загружается, либо один из стилей, скриптов, картинок загружается (последнее с оговорками про асинхронность и прочее).

Т.е. самый простой вариант это подгрузить "картинку", при запросе которой сервер будет просто ничего не отдавать, но и не закрывать соединение. Тогда в браузере будет показываться статус, что картинка грузится. При нажатии "стоп" браузер вроде разорвет соединение, т.е. сервер это может отследить.

При этом промежуточная прокси может разорвать соединение или может в браузере есть на этот счет какие-то таймауты, я точно не знаю, поэтому в браузере скрипт должен отслеживать, если соединение разорвано не по инициативе пользователя и запрашивать картинку заново.

В общем это всё очень сложная и странная машинерия и я не думаю, что так стоит делать. Но если сильно хочется, то как-то так.
Отредактировано 08.11.2023 12:25 vsb . Предыдущая версия . Еще …
Отредактировано 08.11.2023 12:24 vsb . Предыдущая версия .
Re[4]: Как сделать частично загруженную страницу при стриминге
От: Sharov Россия  
Дата: 08.11.23 13:17
Оценка:
Здравствуйте, rameel, Вы писали:

S>>Ну вот со стороны web api хотелось бы знать соотв. события.

R>Добавь в метод параметр CancellationToken

Ну смотрите, у меня web api get запрос, который начинает гнать поток видео(потенциально бесконечно долго),
как мне узнать, что запрашивающая сторона либо закрыла вкладку, либо оборвала запрос. Если с запросом кажется, что
более-менее ясно, скорее всего будет какое-нибудь исключение при доступе к Response.Body, то как быть с вкладкой -- я
Как тут токен может помочь -- я тоже
Кодом людям нужно помогать!
Re[5]: Как сделать частично загруженную страницу при стримин
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 08.11.23 13:34
Оценка:
Здравствуйте, Sharov, Вы писали:

Наверное проще делать через SignalR. Он двухнаправленный.
Посылай команды какие хочешь и обрабатывай на сервере
https://learn.microsoft.com/ru-ru/aspnet/core/signalr/streaming?view=aspnetcore-7.0
и солнце б утром не вставало, когда бы не было меня
Отредактировано 08.11.2023 13:38 Serginio1 . Предыдущая версия .
Re[6]: Как сделать частично загруженную страницу при стримин
От: Sharov Россия  
Дата: 08.11.23 13:44
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>Наверное проще делать через SignalR. Он двухнаправленный.

S>Посылай команды какие хочешь и обрабатывай на сервере
S>https://learn.microsoft.com/ru-ru/aspnet/core/signalr/streaming?view=aspnetcore-7.0

Нет, пока из-за совместимости так сделать нельзя. Возможно в будущем что-то такое и будет.
Кодом людям нужно помогать!
Re[5]: Как сделать частично загруженную страницу при стриминге
От: rameel https://github.com/rsdn/CodeJam
Дата: 08.11.23 14:24
Оценка: 6 (1)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, rameel, Вы писали:


S>Ну смотрите, у меня web api get запрос, который начинает гнать поток видео(потенциально бесконечно долго),

S>как мне узнать, что запрашивающая сторона либо закрыла вкладку, либо оборвала запрос. Если с запросом кажется, что
S>более-менее ясно, скорее всего будет какое-нибудь исключение при доступе к Response.Body, то как быть с вкладкой -- я
S>Как тут токен может помочь -- я тоже

Когда запрос оборвется, token.IsCancellationRequested вернет true. Попытка записать что-то в Response.Body, когда запрос оборвали не приводит к исключению, по крайней мере в моем случае никаких исключений не наблюдал ни раньше ни сейчас (Сейчас вот проверил, никаких исключений)
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[6]: Как сделать частично загруженную страницу при стримин
От: Sharov Россия  
Дата: 08.11.23 14:59
Оценка:
Здравствуйте, rameel, Вы писали:

S>>Ну смотрите, у меня web api get запрос, который начинает гнать поток видео(потенциально бесконечно долго),

S>>как мне узнать, что запрашивающая сторона либо закрыла вкладку, либо оборвала запрос. Если с запросом кажется, что
S>>более-менее ясно, скорее всего будет какое-нибудь исключение при доступе к Response.Body, то как быть с вкладкой -- я
S>>Как тут токен может помочь -- я тоже
R>Когда запрос оборвется, token.IsCancellationRequested вернет true. Попытка записать что-то в Response.Body, когда запрос оборвали не приводит к исключению, по крайней мере в моем случае никаких исключений не наблюдал ни раньше ни сейчас (Сейчас вот проверил, никаких исключений)

Можно пример, а то не догоняю куда конкретно добавить токен?

УПД: Разобрался, что CopyToAsync принимает ct. Ну а кто и как его будет активировать?
Кодом людям нужно помогать!
Отредактировано 08.11.2023 15:14 Sharov . Предыдущая версия .
Re[7]: Как сделать частично загруженную страницу при стриминге
От: rameel https://github.com/rsdn/CodeJam
Дата: 08.11.23 15:14
Оценка: 12 (1)
Здравствуйте, Sharov, Вы писали:

S>Можно пример, а то не догоняю куда конкретно добавить токен?


Добавляешь как параметр твоего метода-endpoint'а. Инфраструктура сама прокинет его в твой метод. Этот токен связан с текущим запросом.

public async Task<IActionResult> Get123(CancellationToken cancellationToken)
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[8]: Как сделать частично загруженную страницу при стриминге
От: Sharov Россия  
Дата: 08.11.23 15:41
Оценка:
Здравствуйте, rameel, Вы писали:

R>Добавляешь как параметр твоего метода-endpoint'а. Инфраструктура сама прокинет его в твой метод. Этот токен связан с текущим запросом.

R>
R>public async Task<IActionResult> Get123(CancellationToken cancellationToken)
R>


Кажется, оно, благодарю:

    [HttpGet(Name = "streamer")]
    public async Task<IActionResult> Get2(CancellationToken cancellationToken)
    {
        
        using (var tcpClient = new TcpClient())
        {
            await tcpClient.ConnectAsync("localhost", 5555, cancellationToken);

            using (var netStream = tcpClient.GetStream())
            {
               
                Response.ContentType = "multipart/x-mixed-replace; boundary=abcd";
                var ns = netStream;
                var tcpCl = tcpClient;
                Response.OnCompleted(() =>
                {
                    ns?.Dispose();
                    tcpCl?.Dispose();
                    return Task.CompletedTask;
                });
                await netStream.CopyToAsync(Response.Body,1024*1024, cancellationToken);
            }
        }
        return Ok();
    }



Т.е. теперь при закрытии страницы в браузере OnCompleted отрабатывает нормально. Интересно, а без ct и закрытия страницы, поток так и будет куда-то писать данные?
Т.е. я зыкрыл страницу, что стало с Response.Body? Я не пойми куда гоню поток и трачу ресурсы...

Да и еще (дурацкий) вопрос: а почему до return Ok() я не дохожу в случае отмены (например, закрытия страницы)? Ну типа запись в поток завершилась,
идем дальше.
Кодом людям нужно помогать!
Re[9]: Как сделать частично загруженную страницу при стримин
От: rameel https://github.com/rsdn/CodeJam
Дата: 08.11.23 16:31
Оценка: 12 (1)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, rameel, Вы писали:


S>Интересно, а без ct и закрытия страницы, поток так и будет куда-то писать данные?

S>Т.е. я зыкрыл страницу, что стало с Response.Body? Я не пойми куда гоню поток и трачу ресурсы...

Потому и существует CancellationToken. А вот что стало с Response.Body, то это надо внутрь заглянуть, что там в кишках происходит


S>Да и еще (дурацкий) вопрос: а почему до return Ok() я не дохожу в случае отмены (например, закрытия страницы)? Ну типа запись в поток завершилась,

S>идем дальше.

Скорее всего один из метотодов ReadAsync / WriteAsync выбросил исключение OperationCanceledException, через cancellationToken.ThrowIfCancellationRequested() или возможно исключение TaskCanceledException от Task.FromCanceled
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Отредактировано 08.11.2023 16:34 rameel . Предыдущая версия .
Re[10]: Как сделать частично загруженную страницу при стримин
От: Sharov Россия  
Дата: 08.11.23 21:27
Оценка:
Здравствуйте, rameel, Вы писали:

S>>Интересно, а без ct и закрытия страницы, поток так и будет куда-то писать данные?

S>>Т.е. я зыкрыл страницу, что стало с Response.Body? Я не пойми куда гоню поток и трачу ресурсы...
R>Потому и существует CancellationToken. А вот что стало с Response.Body, то это надо внутрь заглянуть, что там в кишках происходит


Еще дурацкий вопрос -- я историю развития не знаю, ct всегда существовал или ms его позже добавила?
Если так, то как раньше обходились?

S>>Да и еще (дурацкий) вопрос: а почему до return Ok() я не дохожу в случае отмены (например, закрытия страницы)? Ну типа запись в поток завершилась,

S>>идем дальше.
R>Скорее всего один из метотодов ReadAsync / WriteAsync выбросил исключение OperationCanceledException, через cancellationToken.ThrowIfCancellationRequested() или возможно исключение TaskCanceledException от Task.FromCanceled

Врубил все исключения, ничего не появилось, output window ничего такого про исключения не написал.
Очень странно. По идее в данном случае должно прерываться при любом исключении, даже если оно будет
перехвачено (хотя тут уже не уверен).
Кодом людям нужно помогать!
Re[11]: Как сделать частично загруженную страницу при стримин
От: rameel https://github.com/rsdn/CodeJam
Дата: 09.11.23 08:51
Оценка: 6 (1)
Здравствуйте, Sharov, Вы писали:

S>Еще дурацкий вопрос -- я историю развития не знаю, ct всегда существовал или ms его позже добавила?


Точно не помню, скорее всего с появлением Task, а это вроде в 4 дотнете фреймворк который.

S>Если так, то как раньше обходились?


Хороший вопрос, деталей уже не помню, были события жизненного цикла по которым можно было понять что и как, типа BeginRequest, EndRequest и прочие у HttpApplication. Были всякие соглашения, что методы с определенным названием у модулей, global.asax.cs и прочее, автоматом подписывались на события приложения, например, Application_EndRequest. Не так просто как сейчас конечно.

S>Врубил все исключения, ничего не появилось, output window ничего такого про исключения не написал.

S>Очень странно. По идее в данном случае должно прерываться при любом исключении, даже если оно будет
S>перехвачено (хотя тут уже не уверен).

Поставь уровень логирования "Debug" в appsettings, посмотри что в консоль выводится. Или оберни метод в try-catch.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[12]: Как сделать частично загруженную страницу при стримин
От: Sharov Россия  
Дата: 09.11.23 09:17
Оценка:
Здравствуйте, rameel, Вы писали:


S>>Еще дурацкий вопрос -- я историю развития не знаю, ct всегда существовал или ms его позже добавила?

R>Точно не помню, скорее всего с появлением Task, а это вроде в 4 дотнете фреймворк который.

Я про конкретно webapi, а то они могли это по традиции продолбать, а выходить из положения как-то надо было.
А про ct b task я в курсе -- начало 10-х.

S>>Врубил все исключения, ничего не появилось, output window ничего такого про исключения не написал.

S>>Очень странно. По идее в данном случае должно прерываться при любом исключении, даже если оно будет
S>>перехвачено (хотя тут уже не уверен).
R>Поставь уровень логирования "Debug" в appsettings, посмотри что в консоль выводится. Или оберни метод в try-catch.

Ничего про исключение нету -- , всюду поставил debug (asp.net тоже), остановка на всех clr исключениях
  Лог
Microsoft.AspNetCore.Server.Kestrel.Connections: Debug: Connection id "0HMV10CQV0O98" accepted.
Microsoft.AspNetCore.Server.Kestrel.Connections: Debug: Connection id "0HMV10CQV0O98" started.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/1.1 GET http://localhost:5030/Streamer — —
'StreamerTest.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.14\System.Threading.Tasks.dll'.
Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware: Debug: Wildcard detected, all requests with hosts will be allowed.
Microsoft.AspNetCore.Routing.Matching.DfaMatcher: Debug: 2 candidate(s) found for the request path '/Streamer'
Microsoft.AspNetCore.Routing.Matching.DfaMatcher: Debug: Endpoint 'StreamerTest.Controllers.StreamerController.Get123 (StreamerTest)' with route pattern 'Streamer' is valid for the request path '/Streamer'
Microsoft.AspNetCore.Routing.Matching.DfaMatcher: Debug: Endpoint 'StreamerTest.Controllers.StreamerController.CreateFooter (StreamerTest)' with route pattern 'Streamer' is valid for the request path '/Streamer'
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware: Debug: Request matched endpoint 'StreamerTest.Controllers.StreamerController.Get123 (StreamerTest)'
'StreamerTest.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.14\System.Text.RegularExpressions.dll'.
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware: Debug: Static files was skipped as the request already matched an endpoint.
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint 'StreamerTest.Controllers.StreamerController.Get123 (StreamerTest)'
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Route matched with {action = "Get123", controller = "Streamer"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.IActionResult] Get123() on controller StreamerTest.Controllers.StreamerController (StreamerTest).
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Execution plan of authorization filters (in the following order): None
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Execution plan of resource filters (in the following order): None
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Execution plan of action filters (in the following order): Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter (Order: -3000), Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter (Order: -2000)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Execution plan of exception filters (in the following order): None
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Execution plan of result filters (in the following order): Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter (Order: -2000)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Executing controller factory for controller StreamerTest.Controllers.StreamerController (StreamerTest)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Debug: Executed controller factory for controller StreamerTest.Controllers.StreamerController (StreamerTest)
'StreamerTest.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.14\System.Net.NameResolution.dll'.
'StreamerTest.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\6.0.14\Microsoft.AspNetCore.WebUtilities.dll'.
Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets: Debug: Connection id "0HMV10CQV0O98" received FIN.
Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets: Debug: Connection id "0HMV10CQV0O98" sending FIN because: "The client closed the connection."
Microsoft.AspNetCore.Server.Kestrel.Connections: Debug: Connection id "0HMV10CQV0O98" disconnecting.
Кодом людям нужно помогать!
Re[13]: Как сделать частично загруженную страницу при стримин
От: rameel https://github.com/rsdn/CodeJam
Дата: 09.11.23 10:03
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Ничего про исключение нету -- , всюду поставил debug (asp.net тоже), остановка на всех clr исключениях


Странно, тогда оберни в try-catch и посмотри.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[14]: Как сделать частично загруженную страницу при стримин
От: Sharov Россия  
Дата: 09.11.23 10:09
Оценка:
Здравствуйте, rameel, Вы писали:

S>>Ничего про исключение нету -- , всюду поставил debug (asp.net тоже), остановка на всех clr исключениях

R>Странно, тогда оберни в try-catch и посмотри.

Забыл упомянуть, что обернул:
  код
    [HttpGet(Name = "streamer")]
    public async Task<IActionResult> Get123()
    {
        try
        {
            using (var tcpClient = new TcpClient())
            {
                await tcpClient.ConnectAsync("localhost", 5555);
                using (var netStream = tcpClient.GetStream())
                {
                    Response.ContentType = "multipart/x-mixed-replace; boundary=abcd";

                    await netStream.CopyToAsync(Response.Body);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }

        return Ok();



    }
Кодом людям нужно помогать!
Re: fyi: ложная тревога
От: Sharov Россия  
Дата: 13.11.23 17:37
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте.


S>Дан сл. код:

S>
S> [HttpGet(Name = "streamer")]
S>        public async Task<IActionResult> Get123()
S>        {
S>            using (var tcpClient = new TcpClient())
S>            {
S>                await tcpClient.ConnectAsync("localhost", 5555);
S>                using (var netStream = tcpClient.GetStream())
S>                {
S>                    Response.ContentType = "multipart/x-mixed-replace; boundary=abcd";
S>                    await netStream.CopyToAsync(Response.Body);
S>                }
S>            }

S>            return Ok();
S>        }
S>


S>[cut=Клиент]

S>[idl]

S><html style="height: 100%;">

S> <head>
S> <meta name="viewport" content="width=device-width, minimum-scale=0.1">
S> </head>
S> <body style="margin: 0px; height: 100%; background-color: rgb(14, 14, 14);">
S> <img style="display: block;-webkit-user-select: none;margin: auto;background-color: hsl(0, 0%, 25%);" src="http://localhost:5030/Streamer" width="219" height="184">
S> </body>
S></html>


В общем, все работает как надо. Серверный код выше возвращает поток некоторых изображений, браузер в свою очередь генерирует код страницы (см. выше клиента).
Т.е. если я из браузера обращаюсь к соотв. апи. Я думал, что этот html кем-то сверстан и в нем делается запрос в соотв. api.
Далее, я скопировал этот html для локальных тестов и открывал как локальный файл в браузере, файл сразу грузился и гнал поток.
Что как бы не совпадало с ожидаемым поведением -- ведь это не страница видеоплейера, где страница загрузилась целиком и
можно отдельно управлять медиапотоком, а по сути медиапоток и есть, т.е. страница не должна загрузиться раньше, чем загрузится поток (т.е. страница
находится в ожидании (загрузки потока) ).
Короче, просто неправильно тестировал апи -- надо было через браузер, а не через автосгенеренный файл.
Кодом людям нужно помогать!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.