Estoy grabando audio y enviándolo como un blob a un servidor nodejs. El servidor nodejs luego lo envía a todos los usuarios conectados que no están grabando actualmente.
Enviando el blob:
mediaRecorder.onstop = function(e) { var blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' }); socket.emit('radio', blob); };Servidor que recibe el blob:
socket.on('radio', function(blob) { socket.broadcast.emit('voice', blob); });Oyente que recibe el blob:
socket.on('voice', function(arrayBuffer) { var blob = new Blob([arrayBuffer], { 'type' : 'audio/ogg; codecs=opus' }); var audio = document.getElementById('audio'); audio.src = window.URL.createObjectURL(blob); audio.play(); });Esto funciona en todos los navegadores/dispositivos excepto safari y cualquier dispositivo ios. Yendo más allá con el inspector de safari, encontré esto:
¿Safari requiere algo más en sus encabezados para que los objetos blob se interpreten correctamente? Investigué los tipos de audio aceptados, probé aac/mp3/ogg sin ningún éxito. Después de leer más, escuché referencias al hecho de que hay un error con la transmisión de datos de audio / video de blob en Safari e IOS, aunque no tengo muy claros los detalles.
¡La orientación en la dirección del rito sería muy útil!
EDITAR: se parece a esta línea audio.src = window.URL.createObjectURL(blob); en el blob receptor es lo que está causando los errores de blob (imagen que vinculé)
EDIT 2: Traté de ver si usar otro formato que no sea blob funcionaría, optando por una cadena codificada en base64. Parece que esto funciona en todos los dispositivos y navegadores excepto en IOS y Safari. Tengo la impresión de que tiene algo que ver con la forma en que IOS interpreta/carga los datos...
Para mí, la solución fue insertar un elemento fuente en el elemento de audio y usar el atributo sourceElement.src para hacer referencia al blob. Ni siquiera necesité adjuntar el elemento de audio al DOM. Ejemplo a continuación, espero que ayude a alguien.
var audioElement = document.createElement('audio') var sourceElement = document.createElement('source') audioElement.appendChild(sourceElement) sourceElement.src = '<your blob url>' sourceElement.type = 'audio/mp3' // or whatever audioElement.load() audioElement.play()No he podido encontrar una solución usando un elemento de audio, sin embargo, Web Audio Api parece funcionar: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
var audioContext = new (window.AudioContext || window.webkitAudioContext); socket.on('voice', function(arrayBuffer) { audioContext.decodeAudioData(arrayBuffer, audioData => { var source = audioContext.createBufferSource(); source.buffer = audioData; source.connect(audioContext.destination); source.start() });Es posible que aún tenga un problema en iOS, ya que cualquier audio/video debe ser activado por una acción del usuario.
Tuve un problema similar esta semana. Estaba grabando el audio en Safari y el blob de audio se generaba perfectamente. Pero cuando traté de enviar el blob al servidor, no llegaban datos. La siguiente solución lee el blob con File Reader para convertirlo a base64 y luego enviarlo al servidor. Esto es lo que funcionó para mí:
const reader = new FileReader(); reader.readAsDataURL(audioBlob); reader.onloadend = () => { const base64data = reader.result; const audioName = uuid.v4() + '.mp3'; this.http.post(this.app.cloudStorageEndpoint + '/audios/local?audioName=' + audioName, base64data , header).subscribe( res => { resolve(audioName); }, err => { reject(err); } ); };Probé con Safari 12 tanto en iPad como en iPhone y funcionó bien.