A detailed explanation of the HTML5 recording step-by-step tour, and a detailed explanation of the html5 pitfall tour
Opening Remarks
One case of a while ago was to develop an audio courseware. After importing documents, images, and other resources, the page became similar to a PPT layout. Then, select an image and insert the audio, two modes are available: single-page editing and global editing. There are two audio import methods, one is to import from the resource library, and the other is to mention the recording.
To be honest, I have never touched the HTML5 Audio API in the beginning, and should be optimized based on the code before we took over. Of course, there are also many pitfalls. This time, we will also talk about these pitfalls (the initialization and acquisition of some basic objects will be omitted, because these contents are not the focus of this time, if you are interested, you can find the documents on the MDN ):
- Compatibility of calling Audio API
- Obtain the audio size (frequency)
- Compatibility of paused recordings
- Obtain the current recording time
Preparation before recording
Before starting the recording, you must obtain whether the current device supports the Audio API. The early method navigator. getUserMedia has been replaced by navigator. mediaDevices. getUserMedia. Normally, most modern browsers now support the use of navigator. mediaDevices. getUserMedia. Of course, the Compatibility Statement is also provided on the MDN.
const promisifiedOldGUM = function(constraints) { // First get ahold of getUserMedia, if present const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // Some browsers just don't implement it - return a rejected promise with an error // to keep a consistent interface if (!getUserMedia) { return Promise.reject( new Error('getUserMedia is not implemented in this browser') ); } // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise return new Promise(function(resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); });}; // Older browsers might not implement mediaDevices at all, so we set an empty object firstif (navigator.mediaDevices === undefined) { navigator.mediaDevices = {};} // Some browsers partially implement mediaDevices. We can't just assign an object// with getUserMedia as it would overwrite existing properties.// Here, we will just add the getUserMedia property if it's missing.if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = promisifiedOldGUM;}
This method is asynchronous, so we can prompt devices that are not compatible.
Navigator. mediaDevices. getUserMedia (constraints ). then (function (mediaStream) {// succeeded}, function (error) {// failed const {name} = error; let errorMessage; switch (name) {// The user rejects case 'notallowederror ': case 'permissiondeniederror': errorMessage = 'user has disabled the webpage to call the recording device'; break; // The case 'notfounderror' is not connected to the recording device ': case 'devicesnotfounderror ': errorMessage = 'Recording device not found'; break; // other error cases 'notorortederror ': errorMessage = 'Recording not supported'; break; default: errorMessage = 'Recording call error'; window. console. log (error) ;}return errorMessage ;});
If everything goes well, we can proceed to the next step.
(The method for obtaining the context is omitted here, because this is not the focus of this time)
Start recording and pause recording
A special point here is that an intermediate variable needs to be added to identify whether or not the current recording is in progress. On Firefox, we found a problem where the recording process was normal. However, when we clicked suspend, we found that it could not be paused. At that time, we used the disconnect method. This method does not work. This method requires disconnecting all connections. Later, it was found that an intermediate variable this. isRecording should be added to determine whether the recording is currently in progress. When you click Start, set it to true and set it to false when paused.
When we start recording, there will be a recording listening event onaudioprocess. If true is returned, the stream will be written. If false is returned, the stream will not be written. Therefore, this. isRecording is determined. If it is false, return directly.
// Initialize const audioContext = new AudioContext (); const sourceNode = audioContext. createMediaStreamSource (mediaStream); const scriptNode = audioContext. createScriptProcessor (BUFFER_SIZE, INPUT_CHANNELS_NUM, OUPUT_CHANNELS_NUM); sourceNode. connect (this. scriptNode); scriptNode. connect (this. audioContext. destination); // the process of listening to the recording scriptNode. onaudioprocess = event =>{ if (! This. isRecording) return; // determine whether to record this. buffers. push (event. inputBuffer. getChannelData (0); // obtain the data of the current channel and write it to the array };
Of course, there will also be a pitfall, that is, it cannot be used any more. It comes with a method to obtain the current recording duration, because it is not actually a real pause, but not writing a stream. So we also need to get the duration of the current recording, which needs to be obtained through a formula.
Const getDuration = () =>{ return (4096 * this. buffers. length)/this. audioContext. sampleRate // 4096 is the length of a stream, sampleRate is the sampling rate}
In this way, you can obtain the correct recording duration.
End recording
To end the recording, I pause the recording first, and then perform the audition or other operations first, and then set the array length of the stored stream to 0.
Acquisition frequency
getVoiceSize = analyser => { const dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); const data = dataArray.slice(100, 1000); const sum = data.reduce((a, b) => a + b); return sum;};
See https://developer.mozilla.org/zh-CN/docs/Web/API/AnalyserNode/frequencyBinCount for details
Others
- HTTPS: In chrome, you must have HTTPS for the entire site.
- : JSSDK must be called in a built-in browser.
- Audio Format Conversion: there are many ways to convert the audio format. Most of the information that can be found is basically copied to each other. Of course, there is still a problem with audio quality, so we will not go into details here.
Conclusion
Most of the problems encountered this time are compatibility issues, so there were a lot of pitfalls on it, especially mobile terminals. At the beginning, there were some errors in the preparation of records due to incorrect recording time, this can cause direct freezing. This experience also makes up for some gaps in the HTML5 API. Of course, the most important thing is to remind everyone that this native API document is still simple and rough to view the MDN directly!
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.