title: NodeJS mp3 streaming not working in browsers
body: <p>I'd like to stream MP3 audio files from a NodeJS / ExpressJS backend. I found some code in forums to begin with (e.g. here <a href="https://stackoverflow.com/questions/49524238/stream-mp3-file-express-server-with-ability-to-fast-forward-rewind">stream mp3 file express server with ability to fast forward/rewind</a>), however it doesn't seem to work for me. I have the below code:</p>
  
  <pre><code>const express = require('express');
  const path = require('path');
  const fs = require('fs');
  
  const app = express();
  
  app.get('/', (req, res) =&gt; {
      res.sendFile(path.join(__dirname, 'index.html'));
  });
  
  app.get('/api/play', (req, res) =&gt; {
      var music = path.join('Z:', 'Music', 'Metallica', "Kill 'Em All", '01 - Hit the Lights.mp3');
      var stat = fs.statSync(music);
      var range = req.headers.range;
      var readStream;
  
      if (range != undefined) {
          var parts = range.replace(/bytes=/, '').split('-');
          var partialStart = parts[0];
          var partialEnd = parts[1];
  
          if (isNaN(partialStart) || partialStart == '') {
              partialStart = '0';
          }
  
          if (isNaN(partialEnd) || partialEnd == '') {
              partialEnd = stat.size - 1;
          }
  
          var start = parseInt(partialStart, 10);
          var end = parseInt(partialEnd, 10);
          var contentLength = end - start + 1;
  
          console.log(`Streaming ${music} as ${contentLength} bytes from ${start} to ${end}`);
  
          res.writeHead(206, {
              'Content-Type': 'audio/mpeg',
              'Content-Length': contentLength,
              'Content-Range': 'bytes=' + start + '-' + end + '/' + stat.size,
              'Accept-Ranges': 'bytes'
          });
  
          readStream = fs.createReadStream(music, { start: start, end: end });
      } else {
          console.log(`Streaming ${music} as ${stat.size} bytes`);
  
          res.header({
              'Content-Type': 'audio/mpeg',
              'Content-Length': stat.size
          });
  
          readStream = fs.createReadStream(music);
      }
  
      readStream.pipe(res);
  
      console.log('Done');
  });
  
  const PORT = process.env.PORT || 5000;
  
  app.listen(PORT, () =&gt; console.log(`Server started on port ${PORT}`));
  </code></pre>
  
  <p>index.html is basically just an audio tag:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html lang="en"&gt;
  
  &lt;head&gt;
      &lt;meta charset="UTF-8"&gt;
      &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
      &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
      &lt;title&gt;Document&lt;/title&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
      &lt;audio controls="controls" preload="all"&gt;
          &lt;source src="http://localhost:5000/api/play" type="audio/mpeg" /&gt;
          Your browser does not support the audio element.
      &lt;/audio&gt;
  &lt;/body&gt;
  
  &lt;/html&gt;
  </code></pre>
  
  <p>When I open the page from a browser, I get the audio tag but it is not playing. No error in the console, and in the network tab I see that the /api/play request is only 229 bytes, with following response headers:</p>
  
  <pre><code>Accept-Ranges: bytes
  Connection: keep-alive
  Content-Length: 4108683
  Content-Range: bytes=0-4108682/4108683
  Content-Type: audio/mpeg
  Date: Mon, 30 Sep 2019 18:01:02 GMT
  X-Powered-By: Express
  </code></pre>
  
  <p>However, when I try the same from the RestMan extension, I get the full 4MB file as a response with below headers:</p>
  
  <pre><code>date: Mon, 30 Sep 2019 17:41:01 GMT
  connection: keep-alive
  x-powered-by: Express
  content-length: 15987040
  content-type: audio/mpeg
  </code></pre>
  
  <p>I tried to execute manually from the RestMan client with different "Accept" headers, "0-" as the browser does, "0-2", "0-200", "100-200", etc, I always get the correct response with the correct amount of bytes (e.g. 101 bytes for "100-200"). So why is it that the browser fails to load the audio? Even when I open the /api/play URL directly, I only get an auto-generated "video" tag but it is not playing, same thing happens.</p>
  
  <p>I also tried MP3 without spaces or special characters in the file name, tried loading it from a directory without spaces or special charactes, load from local drive (Z: is network attached storage), tried loading from same directory as the html, it's always the same.</p>
  
  <p>Please help if you have some idea. I'm not sure if it is a problem or some missing thing on the NodeJS side, or something else entirely.</p>