3 votes

L'appel de Safari à decodeAudioData est erroné avec null alors que Chrome fonctionne

J'utilise getUserMedia() y un mediaRecorder pour enregistrer de l'audio, que je stocke ensuite sous forme de texte encodé en base64 sur un serveur. Plus tard, il est récupéré sur le serveur, stocké côté client, puis, lorsque l'utilisateur clique sur un bouton de lecture, il est désencodé et lu. La lecture fonctionne correctement sur Chrome, mais sur Safari decodeAudioData jette un null err dans la fonction catch. J'ai fait des recherches approfondies, mais je ne vois pas ce qui pourrait provoquer l'exception.

Le code d'enregistrement est le suivant :

      navigator.getUserMedia = ( navigator.getUserMedia ||
                                 navigator.webkitGetUserMedia ||
                                 navigator.mozGetUserMedia ||
                                 navigator.msGetUserMedia);
      if (navigator.getUserMedia) {
        //console.log('getUserMedia supported.');
        navigator.getUserMedia (
          { // constraints - only audio needed for this app
            audio: true
          },
          // Success callback
          function(stream) {
            const mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.ondataavailable = audio.saveRecordedAudio;
          });
       }

Le code de lecture est le suivant :

      const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
      const source = audioCtx.createBufferSource();
      const binaryAudioBlob = audio.b64toBlob(b64String);
      const reader = new FileReader();
      reader.addEventListener("loadend", function() {
        const bufferArray = reader.result;
        audioCtx.decodeAudioData(bufferArray, (buffer) => {
          source.buffer = buffer;
          source.connect(audioCtx.destination);
          source.start(0);
          console.log('started audio from blob');
        }, function(e){ 
          console.log("Error with decoding audio data" + e);  // e is null
        });
      });
      reader.readAsArrayBuffer(binaryAudioBlob);

où les b64toBlob est :

    b64toBlob: (b64Data, contentType, sliceSize) => {
      contentType = contentType || '';
      sliceSize = sliceSize || 512;

      const byteCharacters = atob(b64Data);
      const byteArrays = [];

      for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize);

        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }

        const byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
      }

      const blob = new Blob(byteArrays, {type: contentType});
      return blob;
    }

L'audio a été enregistré avec Chrome. Est-il possible que Chrome encode l'audio dans un format que Safari ne peut pas lire ? D'après ce que je sais, le format par défaut est le WAV, donc je pense que Safari peut lire ce format (par opposition à Ogg).

Tous les conseils sont les bienvenus.

1voto

Kaiido Points 35595

Le format par défaut utilisé par les navigateurs Chrome et Firefox pour enregistrer un flux audio à l'aide du MediaRecorder est le suivant Opus .

Safari n'est pas en mesure de lire ce format, c'est pourquoi AudioContext.decodeAudioData() échouera avec une telle entrée.

0voto

AnthumChris Points 1778

Safari 11+ lit les fichiers Opus avec WebAssembly. Vous devrez contourner decodeAudioData() et utiliser directement l'API Web Audio. Voir les exemples ci-dessous :

https://fetch-stream-audio.anthum.com/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X