javascript 如何将blob URL转换为音频文件并保存到服务器

kdfy810k  于 2023-02-11  发布在  Java
关注(0)|答案(2)|浏览(711)

我已经成功地录制并添加了录制的音频,并将其放置在HTML页面的 audio 标记中。
<audio controls="" src="blob:https://localhost:3000/494f62b9-0513-4d1c-9206-6569083a2661"></audio>
另外,我已经成功地使用下面这行代码从source标记中获取了blob源URL:
var source = document.getElementById("Audio").src;
这是我的blob网址:
二进制大对象:https://本地主机:3000/494 f62 b 9 -0513- 4d 1c-9206- 6569083 a2661
现在,我如何将blob源URL转换为音频文件并将其发送到我的服务器?
因为我使用这个记录器API在所有浏览器上工作,所以我只有这样的机会:获取blob源代码,然后将其转换为音频文件,并使用表单数据将音频文件发送到服务器。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>FeedBack URL</title>
  <link rel="shortcut icon" href="./favicon.ico">
  <meta content="width=device-width" name="viewport">
  <meta name="theme-color" content="#00e5d2">
  <style>
    * {
      padding: 0;
      margin: 0
    }

    a {
      color: #009387;
      text-decoration: none
    }

    a:visited {
      color: #930087
    }

    body {
      margin: 1rem;
      font-family: sans-serif
    }

    main {
      max-width: 28rem;
      margin: 0 auto;
      position: relative
    }

    #controls {
      display: flex;
      margin-top: 2rem
    }

    button {
      flex-grow: 1;
      height: 2.5rem;
      min-width: 2rem;
      border: none;
      border-radius: .15rem;
      background: blue;
      margin-left: 2px;
      box-shadow: inset 0 -.15rem 0 rgba(0, 0, 0, .2);
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center
    }

    button:focus,
    button:hover {
      outline: none;
      background: blue;
    }

    button::-moz-focus-inner {
      border: 0
    }

    button:active {
      box-shadow: inset 0 1px 0 rgba(0, 0, 0, .2);
      line-height: 3rem
    }

    button:disabled {
      pointer-events: none;
      background: #d3d3d3
    }

    button:first-child {
      margin-left: 0
    }

    button svg {
      transform: translateY(-.05rem);
      fill: #000;
      width: 1.4rem
    }

    button:active svg {
      transform: translateY(0)
    }

    button:disabled svg {
      fill: #9a9a9a
    }

    button text {
      fill: #00e5d2
    }

    button:focus text,
    button:hover text {
      fill: #00ffe9
    }

    button:disabled text {
      fill: #d3d3d3
    }

    #formats,
    #mode {
      margin-top: .5rem;
      font-size: 80%
    }

    #mode {
      float: right
    }

    #support {
      display: none;
      margin-top: 2rem;
      color: red;
      font-weight: 700
    }

    #list {
      margin-top: 1.6rem
    }

    audio {
      display: block;
      width: 100%;
      margin-top: .2rem
    }

    li {
      list-style: none;
      margin-bottom: 1rem
    }

    .popup-position {
      display: none;
      position: fixed;
      top: 0;
      left: 0;
      background-color: rgba(0, 0, 0, 0.7);
      width: 100%;
      height: 100%;

      /* // The Modal Wrapper */
    }

    #popup-wrapper {
      text-align: left;
    }

    /* //The Modal Container */
    #popup-container {

      background-color: #fff;
      padding: 20px;
      border-radius: 10px;
      width: 300px;
      margin: 70px auto;
    }

    #closePopup {
      margin-left: 281px;
      margin-top: -18px;
    }
  </style>
</head>

<body>
  <a href="javascript:void(0)" onclick="toggle_visibility('contact-popup');">Open Popup</a>
  <div class="popup-position" id="contact-popup">
    <div class="popup-wrapper">
      <div id="popup-container">
        <h5>Feedback</h5>
        <p id="closePopup"><a href="javascript:void(0)" style="color: red;" title="Close"
            onclick="toggle_visibility('contact-popup');">X</a></p>
        <main>
          <div id="controls">
            <button id="record" disabled="" autocomplete="off" title="Record">
              <svg viewBox="0 0 100 100" id="recordButton">
                <circle cx="50" cy="50" r="46"></circle>
              </svg>
            </button>
            <button id="pause" disabled="" autocomplete="off" title="Pause">
              <svg viewBox="0 0 100 100">
                <rect x="14" y="10" width="25" height="80"></rect>
                <rect x="62" y="10" width="25" height="80"></rect>
              </svg>
            </button><button id="resume" disabled="" autocomplete="off" title="Resume">
              <svg viewBox="0 0 100 100">
                <polygon points="10,10 90,50 10,90"></polygon>
              </svg>
            </button><button id="stop" autocomplete="off" disabled="" title="Stop">
              <svg viewBox="0 0 100 100">
                <rect x="12" y="12" width="76" height="76"></rect>
              </svg>
            </button>
          </div>
          <div id="mode">
            Native support,<a href="?polyfill">force polyfill</a>
          </div>
          <div id="formats"></div>
          <div id="support">
            Your browser doesn’t support MediaRecorder
            So please use chrome or edge or mozilla
          </div>
          <ul id="list"></ul>
          <form enctype="multipart/form-data"></form>
            <input id="image-file" type="file" hidden />
            <button type="button" id="formSubmit" onclick="sendto();">Submit</button>
          </form>
        </main>
        <div class="modal-footer">
        </div>
      </div>
    </div>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

  <script>
    (function () {
      var a, i, b, d, f, g, l = ["start", "stop", "pause", "resume"],
        m = ["audio/webm", "audio/ogg", "audio/wav"],
        j = 1024,
        k = 1 << 20;

      function n(e) {
        var r, $ = Math.abs(e);
        return $ >= k ? (r = "MB", e /= k) : $ >= j ? (r = "KB", e /= j) : r = "B", e.toFixed(0).replace(
          /(?:\.0*|(\.[^0]+)0+)$/, "$1") + " " + r;
      }

      function e(e) {
        i.innerHTML = "", navigator.mediaDevices.getUserMedia({
          audio: !0
        }).then(function (r) {
          a = new MediaRecorder(r), l.forEach(function (e) {
            a.addEventListener(e, t.bind(null, e));
          }), a.addEventListener("dataavailable", s), "full" === e ? a.start() : a.start(1e3);
        }), b.blur(), setTimeout(myFunction, 16000);
      }

      function o() {
        a.stop(), a.stream.getTracks()[0].stop(), g.blur();
      }

      function p() {
        a.pause(), d.blur();
      }

      function q() {
        a.resume(), f.blur();
      }

      function s(e) {
        var r = document.createElement("li"),
          $ = document.createElement("strong");
        $.innerText = "dataavailable: ", r.appendChild($);
        var a = document.createElement("span");
        a.innerText = e.data.type + ", " + n(e.data.size), r.appendChild(a), a.setAttribute("id", "span");
        var o = document.createElement("audio");
        o.controls = !0, o.src = URL.createObjectURL(e.data), o.setAttribute("id", "Audio"), r.appendChild(o), i
          .appendChild(r);
      }

      function t(e) {

        var r = document.createElement("li");
        r.innerHTML = "<strong>" + e + ": </strong>" + a.state, "start" === e && (r.innerHTML += ", " + a
            .mimeType), i.appendChild(r), "recording" === a.state ? (b.disabled = !0,
            f.disabled = !0, d.disabled = !1, g.disabled = !1) : "paused" === a.state ? (b
            .disabled = !0, f.disabled = !1, d.disabled = !0, g.disabled = !1) : "inactive" === a
            .state && (b.disabled = !1, f.disabled = !0, d.disabled = !0, g
            .disabled = !0);
      }
      i = document.getElementById("list"),
        b = document.getElementById("record"),
        f = document.getElementById("resume"),
        d = document.getElementById("pause"),
        g = document.getElementById("stop"),
        MediaRecorder.notSupported ? (i.style.display = "none",
          document.getElementById("controls").style.display = "none",
          document.getElementById("formats").style.display = "none",
          document.getElementById("mode").style.display = "none",
          document.getElementById("support").style.display = "block") : (document.getElementById("formats")
          .innerText = "Format: " + m
          .filter(function (e) {
            return MediaRecorder.isTypeSupported(e);
          }).join(", "), b.addEventListener("click", e.bind(null,
            "full")), f.addEventListener("click", q), d.addEventListener("click", p),
          g.addEventListener("click", o), b.disabled = !1);
    })();

    function myFunction() {
      document.getElementById("stop").click();
    }

    function toggle_visibility(id) {
      var element = document.getElementById(id);

      if (element.style.display == 'block')
        element.style.display = 'none';
      else
        element.style.display = 'block';
    }

    async function sendto() {
      var source = document.getElementById("Audio").src;

      $.ajax({
        type: 'POST',
        url: "http://localhost:3000/audioUpload",
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function(result) {
        }
      })

  </script>

</body>

</html>

我已经尝试了获取代码

let file = await fetch(source).then(r => r.blob()).then(blobFile => new File([blobFile], fileName, {
                   type: res[0]
               }));

但是它给了我原始数据,我怎么发送和接收原始数据呢?

llmtgqce

llmtgqce1#

首先,您需要一个合适的函数来发送数据,您最初的fetch方法很接近,但并不完美。
让我们考虑下面的函数。它在file参数中接受Blob。这个Blob将在后面的答案中创建。在sendAudioFile函数中创建一个新的FormData对象。将Blob附加到formData。
现在使用POST方法将formData发送到服务器,并使用formDatabody属性。

const sendAudioFile = file => {
  const formData = new FormData();
  formData.append('audio-file', file);
  return fetch('http://localhost:3000/audioUpload', {
    method: 'POST',
    body: formData
  });
};

现在创建你的文件你需要捕获录制的流。现在你直接设置录制到你的音频元素,但这对你获取录制的数据没有任何用处。
getUserMedia的回调函数中添加一个空数组,我们将其命名为data,该数组将捕获所有记录的数据,并使用它来创建一个Blob
dataavailable事件处理程序中,将e.data(记录的数据)推送到data数组。
添加另一个侦听stop事件的事件侦听器。每当记录停止并收集了所有数据时,在stop事件回调中创建Blob。您可以指定文件的MIME type以告知其格式。
现在您已经有了记录数据的Blob,可以将其传递给sendAudioFile函数,该函数将Blob发送到服务器。

navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
  // Collection for recorded data.
  let data = [];

  // Recorder instance using the stream.
  // Also set the stream as the src for the audio element.
  const recorder = new MediaRecorder(stream);
  audio.srcObject = stream;

  recorder.addEventListener('start', e => {
    // Empty the collection when starting recording.
    data.length = 0;
  });

  recorder.addEventListener('dataavailable', event => {
    // Push recorded data to collection.
    data.push(event.data);
  });

  // Create a Blob when recording has stopped.
  recorder.addEventListener('stop', () => {
    const blob = new Blob(data, {
      'type': 'audio/mp3'
    });
    sendAudioFile(blob);
  });

  // Start the recording.
  recorder.start();
});
xriantvc

xriantvc2#

Emiel Zuubier给出了一个很好的答案,如果您需要通过Base64编码的数据URI发送数据,在这种情况下,

blobToBase64(blob) {
    const reader = new FileReader();
    reader.readAsDataURL(blob);
    return new Promise(resolve => {
        reader.onloadend = () => {
            resolve(reader.result);
        };
    });
};

然后像这样将其发送到服务器:

blobToBase64(audioBlob)
    .then(base64Data => {
        const file = "data:audio/webm;base64," + base64Data;
        const formData = new FormData();
        formData.append('file', file);
        return fetch(url, {
            method: 'POST',
            body: formData
        }).then(res => res.json())
    })

相关问题