使用 localForage 存储和检索音频 (mp3)

Posted

技术标签:

【中文标题】使用 localForage 存储和检索音频 (mp3)【英文标题】:Storing and retrieving audio (mp3) with localForage 【发布时间】:2015-01-12 11:48:42 【问题描述】:

我正在开发一个 Ionic / Cordova 应用程序,该应用程序涉及从远程服务器加载三分钟的音频剪辑 (mp3) 并播放它们。

我已按照本教程 - http://www.html5rocks.com/en/tutorials/webaudio/intro/ - 并且加载和播放工作正常。

但是我想在本地存储/缓存加载的 mp3,这样用户只需下载一次,应用程序就可以离线工作。这些文件大约为 750 KB。在下面的示例中,文件只有 74 KB。

在应用程序的其他地方,我正在使用 Mozilla 的 localForage(通过 [ngular-localForage),它特别声明它可用于存储 ArrayBuffers - http://mozilla.github.io/localForage/#setitem

但是我似乎无法以我可以播放的格式检索音频...我怀疑我存储了错误的东西 - 我真的不明白 ArrayBuffer 是什么!

无论如何,这是我的基本代码(目前我正在使用本地文件)。 第一次加载音频播放正确,第二次加载出现错误(见下文):

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();

function loadDingSound() 

    // attempt to retrieve stored file
    $localForage.getItem('ding').then(function (response) 

        if (response) 

            console.log('playing audio from localForage');

            console.log(response);

            context.decodeAudioData(response, function(buffer) 
                playSound(buffer);
            );

         else 

            var request = new XMLHttpRequest();

            request.open('GET', 'audio/ding.mp3', true); // loading local file for now
            request.responseType = 'arraybuffer';

            // Decode asynchronously
            request.onload = function() 

                $localForage.setItem('ding', request.response).then(function () 

                    context.decodeAudioData(request.response, function(buffer) 

                        playSound(buffer);

                    );

                );

            ;
            request.send();
        

    );



function playSound(buffer) 

    var source = context.createBufferSource(); // creates a sound source
    source.buffer = buffer;                    // tell the source which sound to play
    source.connect(context.destination);       // connect the source to the context's destination (the speakers)
    source.start(0);                           // play the source now


// init
loadDingSound();

我在控制台得到的响应如下:

Object  // line 13
Error: Failed to execute 'decodeAudioData' on 'AudioContext': invalid ArrayBuffer for audioData. // line 15

目前我只在 Chrome 中进行了测试,而不是 Cordova 应用程序。

我做错了什么?还是有更好的方法来做到这一点?也许我可以将 MP3 保存到文件系统中...?

【问题讨论】:

【参考方案1】:

无需执行从 mp3 压缩二进制到 PCM 原始浮点类型数组的两次转换,因此避免两次调用 decodeAudioData。另外,让我们问一个更简单的问题,所以暂时忽略 localForage - 只需将对原始音频缓冲区的引用保存到其自己的 var 中以供以后重播:

<html>
<head>
    <title>Test</title>
</head>

<body>

    <script>

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audio_context = new AudioContext();

var stored_buffer = null;

function loadDingSound() 

    if (stored_buffer)   // attempt to retrieve stored file

        console.log('playing audio from localForage');

        playSound(stored_buffer);

     else 

        var request = new XMLHttpRequest();

        var audio_url = "audio/ding.mp3"; // relative path to reach mp3 file

        request.open('GET', audio_url, true); // loading local file for now
        request.responseType = 'arraybuffer';

        // Decode asynchronously
        request.onload = function() 

            audio_context.decodeAudioData(request.response, function(buffer) 

                stored_buffer = buffer; // store buffer for replay later

                playSound(buffer);

            );
        ;
        request.send();
    


function playSound(buffer) 

    var source = audio_context.createBufferSource(); // creates a sound source
    source.buffer = buffer;                    // tell the source which sound to play
    source.connect(audio_context.destination);       // connect source to speakers
    source.start(0);                           // play the source now


// init
loadDingSound();


    </script>

      <body onkeypress="loadDingSound()">

    <button onclick="loadDingSound()">play_again</button>

</body>
</html>

一旦您对此感到满意,然后系上 localForage - 应该很快

【讨论】:

这工作正常,但一旦我从 localForage 检索到 stored_buffer,它就不再工作,我收到此错误:TypeError: Failed to set the 'buffer' property on 'AudioBufferSourceNode': The provided value is not of type 'AudioBuffer'

以上是关于使用 localForage 存储和检索音频 (mp3)的主要内容,如果未能解决你的问题,请参考以下文章

页面缓存离线存储技术localforage(介绍篇)

在Web应用中使用localforage存储离线数据

突破本地离线存储的JS库 localforage

将 localForage 与 Cordova 一起使用的正确方法是啥?

Vue中 引入使用 localforage 改进本地离线存储(突破5M限制)

使用 $localForage.setItem 时,应用程序会冻结几秒钟