Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to analyze streaming audio from Icecast using Web Audio API and createMediaElementSource?

Using the Web Audio API and createMediaElement method you can use a typed array to get frequency data from audio playback in an <audio> element and it works in most browsers as long as the source URL is local (not streaming). See Codepen: http://codepen.io/soulwire/pen/Dscga

Actual Code:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioElement = new Audio('http://crossorigin.me/http://87.230.103.9:80/top100station.mp3'); // example stream

audioElement.crossOrigin = 'anonymous';
audioElement.type = 'audio/mpeg';

var analyser = audioCtx.createAnalyser();

audioElement.addEventListener('canplay', function() {
  var audioSrc = audioCtx.createMediaElementSource(audioElement);
  // Bind our analyser to the media element source.
  audioSrc.connect(analyser);
  audioSrc.connect(audioCtx.destination);
});

var frequencyData = new Uint8Array(20);

var svgHeight = ($window.innerHeight / 2) - 20;
var svgWidth = $window.innerWidth - 20;
var barPadding = '2';

function createSvg(parent, height, width) {
  return d3.select(parent).append('svg').attr('height', height).attr('width', width);
}

var svg = createSvg('.visualizer', svgHeight, svgWidth);

// Create our initial D3 chart.
svg.selectAll('rect')
   .data(frequencyData)
   .enter()
   .append('rect')
   .attr('x', function (d, i) {
      return i * (svgWidth / frequencyData.length);
   })
   .attr('width', svgWidth / frequencyData.length - barPadding);

// Continuously loop and update chart with frequency data.
function renderChart() {
   requestAnimationFrame(renderChart);

   // Copy frequency data to frequencyData array.
   analyser.getByteFrequencyData(frequencyData);

   console.log(frequencyData);

   // Update d3 chart with new data.
   svg.selectAll('rect')
      .data(frequencyData)
      .attr('y', function(d) {
         return svgHeight - d;
      })
      .attr('height', function(d) {
        return d;
      })
      .style('opacity', function(d) {
        return d / 255;
      })
      .attr('fill', function() {
         return 'rgb(255, 255, 255)';
      });
}

// Run the loop
renderChart();

Where .visualizer is an empty <div>

I'm developing a hybrid app for a radio station using Ionic/Angular and the audio stream is through Icecast (http://dir.xiph.org/) and I've run into the following issue: local mp3s are analyzed and visualized no problem however if you use the streaming URL, analyser.getByteFrequencyData is all zeroes in iOS Safari but it plays fine.

So to recap:

compatability table

I know there was a bug in earlier versions of Safari where createMediaElementSource() would fail but if that were still the case then it wouldn't work on the local file?

Any ideas?

like image 704
Geoff Ellerby Avatar asked Mar 28 '16 21:03

Geoff Ellerby


2 Answers

Still not working with Safari and iOS Chrome (which is using Apple WebKit?). Other browsers seem to be fine now. Audio plays fine, CORS is ok - yet Analyser is not working.

This fiddle (not mine) demonstrates the behavior well. Latter uri gets analysed, former not:

  const url = useStream
  ? 'https://c2.radioboss.fm:18071/stream'
  : 'https://twgljs.org/examples/sounds/DOCTOR%20VOX%20-%20Level%20Up.mp3';

Related question in Apple forum (no answers)

like image 85
lardois Avatar answered Nov 13 '22 09:11

lardois


It just is not implemented according to the specs in Safari and will return an array of zeroes instead of frequencies for streams. Many people have observed this behaviour, e.g. http://isflashdeadyet.com/tests/web-audio-visualization/index-analyser.html and https://github.com/Okazari/Rythm.js/issues/7

It is supposted to work according to https://browsersupport.io/AnalyserNode.prototype.getByteFrequencyData

Here you will find that "Safari [is] seemingly reporting no signal (a value of 128) across the board when requesting byte data on an AnalyserNode": http://fourthof5.com/audio-visualisation-with-the-web-audio-api

Test the demo here to see the current status: http://fourthof5.com/assets/posts/audio-visualisation-with-the-web-audio-api/index.html

like image 1
Klaassiek Avatar answered Nov 13 '22 09:11

Klaassiek