dash.js - stuck at buffering when trying to watch (new) live stream

394 views Asked by At

This is my setup:

I have a webpage which uses dash.js to view a live stream. The live stream is coming from my computer which is running OBS and NGINX. This works without a problem except when I call up the webpage within the first 30 seconds (or so) after the stream has started.

I tell dash to open up index.mpd on my computer, but only when it's available. In pseudo code:

START: If index.mpd is available
  initialize stream and view it
Else
  go to START
End

As soon as index.mpd is available, this means there's also a video/audio chunk available so it should be able to start playing. But it stalls instead (grey screen with rotating pin wheel). This probably has to do with the fact the settings ask for a 20 second buffer and a video/audio chunk is 8.3 seconds. (BTW, I have no idea why those chunks are 8.3 seconds - I could not find a setting anywhere in OBS or NGINX that reflects those 8.3 seconds)

The problem is, it never stops stalling (is it trying to buffer? I don't know). Even when all chunks are available and NGINX starts FIFO-ing the chunks. It never recovers from the stall.

Only when I open the page at a time when the entire buffer is available (which, again for some unknown reason, is about 30 seconds instead of the 20 I have set it to) will it start (dis)playing the stream.

Here is the complete NGINXG.conf:

worker_processes  1;
error_log  logs/error.log;

events {
  worker_connections  1024;
}

rtmp {
  server {
    listen 1935;
    chunk_size 4096;

    application live {
      live on;
      interleave on;
      meta on;
      session_relay on;
      max_connections 1500;
      record_path recordings;
      record_suffix all-%d-%b-%y-%T.flv;

      push rtmp://localhost/dash;
    }

    application dash {
      live on;
      dash on;
      dash_nested on;
      dash_cleanup on;
      dash_fragment 5s;
      dash_playlist_length 20s;
      dash_path temp/tmp_dash;
    }
  }
}

http {

  keepalive_timeout   60;
  send_timeout        10;
  keepalive_requests  10;
  client_body_timeout 10;

  sendfile            on;
  include             mime.types;
  default_type        application/octet-stream;

  log_format          main '$remote_addr - $remote_user [$time_local] "$request" '
                           '$status $body_bytes_sent "$http_referer" '
                       '"$http_user_agent" "$http_x_forwarded_for"';

  access_log          logs/access.log  main;

  server {

    listen            8050;

    server_name       localhost;
    access_log        logs/host.access.log  main;
    add_header        Strict-Transport-Security "max-age=63072000;";
    index             index.php index-nginx.html index.html index.htm;

    error_page        500 502 503 504  /50x.html;

    location = /50x.html {
      root              site;
    }


    location / {

      location ~* \.m3u8$ {
        add_header Cache-Control no-cache;
      }

      try_files $uri $uri/ =404;
      add_header 'Access-Control-Allow-Origin' '*' always;
      add_header 'Strict-Transport-Security' 'max-age=31536000';
      add_header 'X-Content-Type-Options' "nosniff" 'always';

      if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Max-Age' 1728000;
        # add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
      }

      if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length';
      }
      if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }

      root site;
      index index.php index.html index-nginx.html index.htm index.m3u8 index.mpd;
    }

    location /stat {
      rtmp_stat all;
      rtmp_stat_stylesheet stat.xsl;
    }

    location /stat.xsl {
      root site;
    }

    location /tmp_dash {
      alias temp/tmp_dash;
      autoindex on;
      autoindex_localtime on;
      autoindex_exact_size off;
      expires -1;

      if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
      }

      if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length';
      }

      if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length';
      }

      types {
        application/dash+xml mpd;
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
        text/html html;
      }

    }

  }

}

And here's the HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <script src="http://cdn.dashjs.org/latest/dash.all.min.js"></script>

    <script>
      window.addEventListener( "load", init );
      var XMLHttp;
      var streamActive = false;
      var url = "/tmp_dash/stream/index.mpd";

      function init(){
        XMLHttp = new XMLHttpRequest();
        XMLHttp.onreadystatechange = function() {
          if( XMLHttp.readyState == 4
            if( XMLHttp.status == 200 ) {
              // Index.mpd exists
              if( ! streamActive ) {
                player = dashjs.MediaPlayer().create();
                player.initialize( document.querySelector( "#videoPlayer" ), url, true);
              }
            } else if( XMLHttp.status == 404 ) {
              setTimeout( checkStreamReady, 5000 ); // Check again in 5 seconds
            }
          }
        }
        checkStreamReady();
      }

      function checkStreamReady() {
        XMLHttp.open( "GET", url, true );
        XMLHttp.send();
      }

    </script>
  </head>

  <body>

    <div id="videocontainer">
      <video id="videoPlayer" controls></video>
    </div>

  </body>
</html>
0

There are 0 answers