9

I am providing audio recording to my users within the browser, using Javascript:

navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => 
{
    stream = _stream;
    recorder = new MediaRecorder(stream);

    recorder.ondataavailable = e => 
    {
        // push data to chunks
        chunks.push(e.data);

        // recording has been stopped
        if(recorder.state == 'inactive') 
        {
            blob = new Blob(chunks, {type: media.type });
            blob_url = URL.createObjectURL(blob);
            
            $('.rec_result_audio').attr({
                'src': blob_url
            });
            
            // send data to server
            // append file to object to be sent
            var filedata = new FormData();
            filedata.append('recfile', blob, blob_url);

            // send by AJAX/POST
        }
    };
}

In PHP I get and store the stream like this:

if(!empty($_FILES)) 
{
    $filename = $_FILES['recfile']['name'];
    $file_locationtmp = $_FILES['recfile']['tmp_name'];
    $filetype = $_FILES['recfile']['type'];
    $filesize_bytes = $_FILES['recfile']['size'];
    
    // add file extension to string
    $_FILES['recfile']['name'] = $_FILES['recfile']['name'].'.ogg';

    // save to filesystem
}

Now the OGG file (webm with opus codec) is stored on the server. However, all the metadata is missing. And thus the playbar does not work. See here for more info: HTML5 Audio - Progressbar/Playbar is not working for OGG audio file / Issue with 206 Partial Content

ogg metadata empty

Length is missing. Also the Bit rate, Channels and Audio sample rate.

Obviously the direct saving to the file system with PHP is not enough.

What is missing in the PHP code, so that the file is recognized as an OGG file later on?

Do I have to add metadata, and if so, how?

Avatar
  • 14,622
  • 9
  • 119
  • 198
  • Related: https://stackoverflow.com/questions/63640361/how-to-add-duration-to-metadata-of-files-recorder-by-mediarecorder – chiliNUT Apr 13 '21 at 05:29
  • Thank you for the hint. This Javascript library would add 21 KB to my main JS file. That's a lot. Is there any way of doing this directly with PHP serverside? – Avatar Apr 13 '21 at 12:19
  • 1
    I just stumbled over https://github.com/JamesHeinrich/getID3 and will report back if this helps to solve the issue. – Avatar Apr 13 '21 at 12:23
  • Oh good call doing it in php – chiliNUT Apr 13 '21 at 19:34
  • As it seems, writing metadata to this webm/audio format is not supported. https://github.com/JamesHeinrich/getID3/issues/307 – Avatar Apr 15 '21 at 05:57

4 Answers4

1

I am probably missing something obvious, but - shouldn't you specify that you want the Javascript stream to be OGG/Vorbis?

recorder = new MediaRecorder(stream, { mimeType: "audio/ogg; codecs=vorbis" });

I might be mistaken, but the file you get:

Now the OGG file (webm with opus codec) is stored on the server. However, all the metadata is missing.

is not actually an OGG file -- it is a WEBM file. As such, giving it an .ogg extension instead of .webm, as you do, probably confuses the system, and that's why the file appears "unreadable and missing metadata".

LSerni
  • 55,617
  • 10
  • 65
  • 107
  • In Chrome I get "Uncaught (in promise) DOMException: Failed to construct 'MediaRecorder': Failed to initialize native MediaRecorder the type provided (audio/ogg; codecs=vorbis) is not supported." – Avatar May 02 '21 at 09:03
  • Well, I am afraid that's your answer then. You need to download the stream in whatever format the browser supports, and then convert it in OGG format (unless you keep it as .webm. what happens if you use a .webm file extension?). – LSerni May 02 '21 at 09:13
0

The easiest solution is to download an already compiled ffmpeg binary and point your script to it. On the FFmpeg Download page refer to the Get the packages section for links to recent static builds for Linux, Windows, and macOS.

You can use shell_exec() as shown in FFmpeg Wiki: PHP and provide the full path to the downloaded binary.

javad shariaty
  • 939
  • 10
  • 14
0

For now I solved the problem only by using ffmpeg for converting the file serverside to oga format - but not directly in PHP.

  1. Install ffmpeg on your server with sudo apt install ffmpeg

  2. Use ffmpeg in your PHP script:

// physical path to uploaded file
$filelocationtmp = $_FILES['recfile']['tmp_name'];

// call ffmpeg script to convert file
shell_exec("ffmpeg -y -i ".$filelocationtmp." -c:a libvorbis -vn -b:a 48k ".$filelocationtmp.".oga");

// rename oga file to original file (overrides original)
shell_exec("mv ".$filelocationtmp.".oga ".$filelocationtmp);

Note: ffmpeg cannot read input file and write output file the same time. That's why the second command line is necessary.



⚠️ This is not a pure PHP solution. So the question is still open.

Avatar
  • 14,622
  • 9
  • 119
  • 198
0

Another option would be to write with the ogg:// wrapper, which knows about the meta-data.
The PECL libvorbis package looks a little dated, but eventually it would still build for PHP 7.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216