Search code examples
blobaudio-streamingweb-audio-apiserver-sent-events

Why is my Blob data not playing in my audio element?


I am using Server Sent events to send an audio/ogg file as a stream from PHP to the client (javascript). The file will be updated with live audio periodically so I want to check for updates (more on that later). At the moment, I am just trying to send some data to get things started. On the client side, I figured I would need to convert the data into a Blob and then use createObjectURL() to set the src attribute of my audio element to receive the stream.

So far, I am receiving data and I can see the data in my console (image below). I am able to convert the data into a blob and create an object url. Playback on my audio element seems to produce empty audio data unfortunately. My code is below.

I tried using the MediaSource constructor and the MediaStream constructor, but I get errors about failing to convert values. I read dozens of questions here on SO as well. But none seem to relate to my situation.

I was thinking maybe my file type is creating the problem. I tried setting it to streams, but no change in results. I have read quite a lot on the API's used here and it seems my design introduces a scenario that the examples do not cover, or am I missing something?

My javascript (client-side):

console.log("getLiveStream") ;
   var first = true ;
   var source = new EventSource("sse.php") ;

   source.onmessage = function( event ) {
      console.log("onmessage") ;
      console.log(event) ;

      if ( first )
         {
         var container = document.createElement("div") ;
         var naudio = document.createElement("audio") ;
         naudio.setAttribute("controls" , "") ;
         container.appendChild(naudio) ;
         document.body.appendChild(container) ;
         var blob = new Blob([event.data] , { type : "audio/ogg; codecs=opus" }) ;
      console.log(blob) ;
         var urldata = window.URL.createObjectURL(blob) ;
         naudio.src = urldata ;
         naudio.load() ;
         naudio.play() ;
         first = false ;
         }

My PHP (server-side):

<?php
header("Content-Type: text/event-stream") ;
header("Cache-Control: no-cache") ;

/* Stream Context */
$options = array(
   "http" => array(
      "method" => "POST",
      "header" => "Content-type: text/event-stream",
      "header" => "Cache-Control: no-cache"
)) ;
$stream = stream_context_create($options) ;

$livefile = "audio.ogg" ;

while (true) {
$liveaudio = file_get_contents($livefile) ;
   /* Every 6 seconds, send a "data" event. */
   echo "data: " . $liveaudio ;
   echo "\n\n" ;
   flush() ;
   ob_flush() ;

   /* Break the loop if the client aborted the connection (closed the page) */
   if (connection_aborted()) { break ; }
   sleep(6) ;
}
exit() ;
?>

My console: enter image description here

EDIT: So, using base64 encoding certainly solved my server side problem (as Touffy pointed out in the comments). Now the client data is populating with useful data. However, any of my attempts for playback still produce nothing. The Blob is created fine. The object url is created. But playback is not happening. Console log produces no errors.


Solution

  • I found the solution. Setting up an AudioContext constructor and passing it to a MediaStream constructor was my solution. But I had to encode the raw data coming from the server first, as Touffy pointed out originally. Javascript handles the base64 encoding well. After setting up my constructors, my audio playback succeeded.