17522


# 質問

サイズの大きいmp3をXHRでロードし、WebAudioAPIを用いて再生しているのですが、ロードが完了するまでの待ち時間が発生します。  
サイズが大きいmp3であっても待ち時間を少なく抑えて再生を開始する方法はありますでしょうか。

たとえば、SoundCloudは再生ボタンをクリックすると即座に再生が開始されます。デベロッパーツールで確認すると再生しながらロードを行っているのがわかります。  
どのような実装でこれを実現しているのか分かっていないのですが、何かしらの方法があるのではないかと考えています。

# 待ち時間が発生してしまう実装

[code]

    (function () {
      window.AudioContext = window.AudioContext || window.webkitAudioContext;
      var context = new AudioContext();
    
      loadSound('./audio/sample.mp3');
    
      function loadSound(url) {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.setRequestHeader('Range', 'bytes=0-');
        request.responseType = 'arraybuffer';
    
        request.onload = function() {
          context.decodeAudioData(request.response, function(buffer) {
            playSound(buffer);
          }, function () {
            console.debug('error');
          });
        };
    
        request.send();
      }
    
      function playSound(buffer) {
        var source = context.createBufferSource();
        source.buffer = buffer;
        source.connect(context.destination);
        source.start(0);
      }
    })();
[/code]


CC BY-SA 3.0
2015-10-10T17:33:23.300
17514
2015-10-17T08:15:00.067
3968
question
javascript
WebAudioAPIでmp3をすべてダウンロードするのを待たずに再生を開始したい


Media Source Extensionsという、JavaScriptでストリーミングするための標準APIがあります。  
これを使ってみるのはいかがでしょうか?

参考  
<https://github.com/72lions/PlayingChunkedMP3MediaSourceAPI>

[Media Source Extensions](http://www.w3.org/TR/media-source/) W3Cでの仕様

### 追記:

デベロッパーツールで音声ファイルのレスポンスのhttp statusを確認したところ、一般的な`200 OK`ではなく、`206 Partial
Content`を返していました。

`206 Partial Content`はサーバーにデータ(今回の場合はmp3)の一部分を要求するものらしいです。  
これを使っているのではないでしょうか?

参考  
RFC: <https://www.rfc-editor.org/rfc/rfc7233>  
<http://blog.cloudpack.jp/2014/08/12/mamma-mia-http-status-code-206-partial-
content/>


CC BY-SA 3.0
2015-10-11T02:02:29.697
17522
2015-10-12T01:25:29.983
2021-10-07T07:05:27.390
-1
5246
17514
answer


`AudioBuffer`はせいぜい1分程度の比較的短めの音声のために設計されていて、たとえばCD一枚74分のデータ全体のような大きなデータを読み込むような目的には向いていません。

> このインターフェースはメモリ上に保持されるオーディオのリソース(ワンショットの音やその他の短いオーディオクリップ)を表します。 そのフォーマットは-1
> ～ +1の名目上の範囲を持つ非インターリーブのIEEE 32ビット・リニアPCMです。 1つ以上のチャンネルを持つ事ができます。
> 典型的には、そのPCMデータは適度に(通常1分以内程度に)短いと見込まれます。
> 音楽の1曲分のような長時間の音に関してはaudio要素とMediaElementAudioSourceNodeによるストリーミングを使うべきです。

<http://g200kg.github.io/web-audio-api-ja/#AudioBuffer>

>
> これらのオブジェクトは短い、一般的には45秒未満の、断片的な音声を保持するために設計されています。それよりも長い音声は、MediaElementAudioSourceNodeのオブジェクトが適しています。

<https://developer.mozilla.org/ja/docs/Web/API/AudioBuffer>

というわけで、`MediaElementAudioSourceNode`を使うのがいいと思います。`MediaElementAudioSourceNode`なら簡単にストリーミング再生で部分的に読み込みながら再生することが可能です。ただし、おそらくないと思いますが、万が一どうしてもXHRで読み込まなければならない理由があるのなら、`MediaElementAudioSourceNode`を使うことはできません。その場合は何らかの方法でオーディオファイルを分割して`AudioBuffer`に読み込むことになるでしょう。

# 追記: `MediaElementAudioSourceNode`で途中から再生するには

[`HTMLMediaElement`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement)の[`currentTime`プロパティ](https://developer.mozilla.org/en-
US/docs/Web/API/HTMLMediaElement/currentTime)で現在の再生位置を設定できます。その後で`play`を呼び出せば途中から再生できます。たとえば、ローカルのオーディオファイルを開いて、ローパスフィルタをかけて途中から再生するコードは次のようになります。

[code]

    var input = document.querySelector("input");
    var audio = document.querySelector("audio");
    
    var context = new AudioContext();
    var source = context.createMediaElementSource(audio);
    var filter = context.createBiquadFilter();
    
    source.connect(filter);
    filter.connect(context.destination);
    
    input.addEventListener("change", function(){
        audio.src = URL.createObjectURL(input.files[0]);
        audio.currentTime = 50; 
        audio.play();
    });
[/code]

[code]

    <input type="file"></input>
    <audio controls />
[/code]


CC BY-SA 3.0
2015-10-13T21:39:00.390
17613
2015-10-17T08:15:00.067
2015-10-17T08:15:00.067
10330
10330
17514
answer