web-dev-qa-db-ja.com

POSTサーバーへのHTML5オーディオデータ

私は現在Webアプリケーションを実装しており、ユーザーにオーディオを録音してから、送信ボタンにPOSTサーバーに録音されたmp3ファイル)を送信します。

私のサーバー(Flask)のメインルート'/'はPOSTリクエストを待っています:

@app.route('/', methods=['GET', 'POST'])
def index():
  if request.method == "GET":
    return render_template('index.html', request="GET")
  else:
    print request.files
    print request.form
    print request.form['file']
    if 'file' not in request.files:
      flash('No file part')
      return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
      flash('No selected file')
      return redirect(request.url)
    if file and allowed_file(file.filename):
      handle_file(file)
    return render_template('index.html', request="POST")

これが私のJSコードです:

Jsfiddle

ここには2つの主要な問題があります。

1)録音後にmp3ファイルをダウンロードすると、メディアプレーヤーで開けません。音声の録音だけで問題が発生しているようです。

2)print request.form POSTリクエストを受け取った後、サーバーでこれを取得します。

ImmutableMultiDict([('file', u'')])

そしてprint request.form['file']は空の行を返します。

なんでこんなことが起こっているの? POSTリクエストに問題がありますか?.

最後に、投稿している文字列をdecodeしてmp3に変換できるようにしたいと考えています。それ、どうやったら出来るの?

:これは同じである必要はありません。タスクは、オーディオを録音してからPOSTそれをサーバーに送信することです。より効率的な方法がある場合は、ヒントを歓迎します。また、ファイルがwavまたはmp3。

14
pavlos163

注:この回答では、chromeとFirefoxの両方で現在の実装のみを扱います。これはすべて、将来変更される可能性があります。


サーバー側のコードに問題がないかどうかはわかりませんが、バイナリデータを文字列として送信しないでください。代わりに、FormDataを使用してマルチパートとして送信します(30%のデータ+整合性を獲得します)。

また、MediaRecorderコードでは、dataavailableイベントごとにファイルをファイナライズしているようです。それは一般的にあなたが望むものではありません。


現在、どのブラウザーもネイティブにmp3として録音をサポートしていません。

var mimes = ['mpeg', 'mpeg3', 'x-mpeg3', 'mp3', 'x-mpeg']
console.log(mimes.some(m=>MediaRecorder.isTypeSupported('audio/'+m)));

したがって、MediaRecorderの方法を使用する場合は、opusコーデックを使用して対応する必要があります。これは、Chromeの場合はwebmに、FFの場合はoggにカプセル化されます。

var enc = ['ogg', 'webm'];
var mime = "";
enc.forEach(e => {
  if (!mime && MediaRecorder.isTypeSupported(`audio/${e};codecs="opus"`)) {
    mime = `audio/${e};codecs="opus"`;
  }
});
console.log(mime);

これで正しいmimeTypeが得られたので、ブラウザにそれを使用するように指示するだけです。

クロムのフィドル

var enc = ['ogg', 'webm'];
var extension = "",
  mime = '';
enc.forEach(e => !extension &&
  (mime = `audio/${e};codecs="opus"`) &&
  MediaRecorder.isTypeSupported(mime) &&
  (extension = e));
navigator.mediaDevices.getUserMedia({
    audio: true
  })
  .then(stream => {
    const chunks = [];
    const rec = new MediaRecorder(stream, {
      mimeType: mime // use the mimeType we've found
    });
    // this is not where we build the file, but where we store the chunks
    rec.ondataavailable = e => chunks.Push(e.data);
    rec.onstop = e => {
      // stop our gUM stream
      stream.getTracks().forEach(t => t.stop());
      // NOW create the file
      let blob = new Blob(chunks, {
        type: mime
      });
      // we could now send this blob : 
      //   let form = new FormData();
      //   form.append('file', blob, 'filename.'+extension;
      //   ... declare xhr
      //   xhr.send(form);
      // but we'll just fetch it for the demo :
      let url = URL.createObjectURL(blob);
      let au = new Audio(url);
      au.controls = true;
      document.body.appendChild(au);
      au.play();
      // and create an downloadable link from it : 
      let a = document.createElement('a');
      a.href = url;
      a.download = 'filename.' + extension;
      a.innerHTML = 'download';
      document.body.appendChild(a);
    };
    rec.start();
    setTimeout(() => rec.stop(), 3000);
  });

または、デフォルトでブラウザにすべてを実行させることもできます。これはファイル拡張子の場合にのみ問題になります...


ここで、wavよりもopusを使用したい場合は、MediaRecorderを解放し、WebAudioAPIを使用して、gUMストリームをそれに渡し、そこからデータを記録することができます。ここでは、簡単にするために recorder.js ライブラリを使用します。

クロムのフィドル

navigator.mediaDevices.getUserMedia({
  audio: true
})
.then(stream => {
  const aCtx = new AudioContext();
  const streamSource = aCtx.createMediaStreamSource(stream);
  var rec = new Recorder(streamSource);
  rec.record();
  setTimeout(() => {
    stream.getTracks().forEach(t => t.stop());
    rec.stop()
    rec.exportWAV((blob) => {
      // now we could send this blob with an FormData too
      const url = URL.createObjectURL(blob);
      let au = new Audio(url);
      au.controls = true;
      document.body.appendChild(au);
      au.play();
      let a = document.createElement('a');
      a.href = url;
      a.innerHTML = 'download';
      a.download = 'filename.wav';
      document.body.appendChild(a);
    });
  }, 3000);
})
<script src="https://rawgit.com/mattdiamond/Recorderjs/master/dist/recorder.js"></script>

そして、もしあなたが本当にmp3が欲しいなら、私はあなたがウェブ上で利用可能なjavascript lameライブラリの一つを使うことができると思います。

5
Kaiido

オーディオblobをBase64に変換して、base64文字列をサーバーに送信してみてください。

function submit(blob) {
  var reader = new window.FileReader();
  reader.readAsDataURL(blob);
  reader.onloadend = function() {

    var fd = new FormData();
    base64data = reader.result;
    fd.append('file', base64data, 'audio.mp3');

    $.ajax({
      type: 'POST',
      url: '/',
      data: fd,
      cache: false,
      processData: false,
      contentType: false,
      enctype: 'multipart/form-data'
    }).done(function(data) {
      console.log(data);
    });
  }

}

次に、サーバーでbase64文字列をバイナリストリームに変換します。

pythonこの投稿をチェックアウトして、Base64をデコードする方法の詳細情報を作成してください。 Python base64 data decode

1
Nadir Laskar