How to save MediaRecorder stream to OGG file in PHP? Including Metadata
Asked Answered
M

4

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?

Municipal answered 11/4, 2021 at 4:31 Comment(5)
Related: #63640861Schaffhausen
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?Municipal
I just stumbled over github.com/JamesHeinrich/getID3 and will report back if this helps to solve the issue.Municipal
Oh good call doing it in phpSchaffhausen
As it seems, writing metadata to this webm/audio format is not supported. 😔 github.com/JamesHeinrich/getID3/issues/307Municipal
Y
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".

Yean answered 30/4, 2021 at 22:32 Comment(3)
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."Municipal
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?).Yean
@Municipal Read the first bytes of any file/stream to identify by that signature if it's an Ogg or WebM (or else). Filename extensions mean nothing. Using ffmpeg only works because it does the same on mystery boxes: identifying the format by its signatures.Sidetrack
Q
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.

Quay answered 13/4, 2021 at 12:51 Comment(3)
Could you add the necessary PHP code to your answer? I have never used ffmpeg before.Municipal
ffmpeg -i input.mp4 -codec:v libtheora -qscale:v 3 -codec:a libvorbis \ -qscale:a 3 -f ogv output.ogvQuay
But I am trying to find a PHP solution that also works on servers that don't come with ffmpeg.Municipal
M
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.

Municipal answered 28/4, 2021 at 7:2 Comment(0)
I
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.

Isomagnetic answered 28/4, 2021 at 7:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.