peaks.js icon indicating copy to clipboard operation
peaks.js copied to clipboard

player can't play the audio after called the setSource function

Open ZYMoridae opened this issue 4 years ago • 12 comments

I am trying to call setSource function to update the wave and audio. After I calling this function, I can see the wave just changed immediatly. However, when I call the play function of the Player, nothing happened.

ZYMoridae avatar Jan 21 '21 22:01 ZYMoridae

Can you share a minimal code example that demonstrates the problem?

chrisn avatar Jan 21 '21 23:01 chrisn

        let blob = new Blob(this.replaceClipCurrentBuffer, {type: 'audio/mp3'})

        let fileReader = new FileReader()
        fileReader.onloadend = (evt) => {
          this.audioContext.decodeAudioData(evt.target.result).then(audioBuffer => {
            let audioSourceElement = document.getElementById('audio')
            audioSourceElement.src = URL.createObjectURL(blob)
            // let convertedBuffer = blobToAudioBuffer(this.audioContext, blob)

            // var audioElement = document.getElementById('audio')
            //
            audioSourceElement.load()

            this.peaksInstance.setSource({
              mediaUrl: audioSourceElement.src,
              webAudio: {
                audioContext: this.audioContext,
                audioBuffer: audioBuffer
              },
            }, (error) => {
              // this.audioBuffer = concatenateBuffer
              console.log('finish')

            })
          }).catch(error => {

          })
        }

        fileReader.readAsArrayBuffer(blob)

ZYMoridae avatar Jan 21 '21 23:01 ZYMoridae

Your example works OK for me - the only difference is that I used <input type="file"> and so I do URL.createObjectURL() using a File and not a Blob. I don't think that's significant though.

Note that the intention with setSource() is that it updates the media element's src for you, and you shouldn't need to call load(). Also, as you have an AudioBuffer you don't also need to pass in the AudioContext.

const options = {
  mediaUrl: URL.createObjectURL(blob),
  webAudio: {
    audioBuffer: audioBuffer
  }
};

peaksInstance.setSource(options, callback);

chrisn avatar Jan 21 '21 23:01 chrisn

@chrisn I just found if i directly access the url of Blob, it takes some time to generate the audio. I am not sure is it because I am building a blob through the audioBuffer? And it might also be reason why the audio can't be played?

ZYMoridae avatar Jan 22 '21 00:01 ZYMoridae

What happens if you set the media element src without calling peaks.setSource()? Does this also stop the audio being played?

What Peaks.js does internally when you call setSource() is change the media element's src, waits for a media element canplay event, then updates the waveform view.

chrisn avatar Jan 22 '21 08:01 chrisn

@chrisn I tryied to set src without calling peaks.setSource() and still unable to play the audio. But I found if I add browser default controls to the audio, it was able to be played. Not sure what's happening behind the curtain.

ZYMoridae avatar Jan 22 '21 23:01 ZYMoridae

Are there any clues in the browser console? I wonder if it's being blocked because of autoplay policy.

chrisn avatar Jan 22 '21 23:01 chrisn

There is no error logs. And I also found if called the URL.createObjectURL(), even for the default browser control bar might take few seconds to let me play. If I clicked the play button before that time, the progress bar just retunred to the zero. However the progress already displayed the duration of the audio.

ZYMoridae avatar Jan 22 '21 23:01 ZYMoridae

@chrisn Looks like I found the issue, if I added preload='auto' to the audio element the issue will be resolved.

ZYMoridae avatar Jan 23 '21 00:01 ZYMoridae

Excellent! I might experiment with preload settings to see if we should anything about that to the documentation.

chrisn avatar Jan 23 '21 00:01 chrisn

For my case, the scenario requires the aduio to be loaded immedaitly after the I set the src attribute. Not sure this preload='auto' should be applied for all the time. But anyway, thanks for the help on this issue! If you need anything from me when doing the experiment, please let me know.

ZYMoridae avatar Jan 23 '21 00:01 ZYMoridae

I had this same issue.. I'm using the new File System Access API and have a FileHandle that points to the local file, but that doesn't appear to be supported by the audio element yet.

So I was attempting to convert the arraybuffer as described in various SO articles:

const file = await track.fileHandle.getFile();
const arraybuffer = await file.arrayBuffer;

const blob = new Blob([arraybuffer], { type: 'audio/mp3' });
const url = window.URL.createObjectURL(blob);

waveform.setSource({ mediaUrl: url, webAudio: { audioBuffer } },
   err => { if (err) console.error(err) });

However that wasn't working. Based on your comments above, I tried just using the file, and that did the trick (no preload='auto' necessary):

const file = await track.fileHandle.getFile();
const url = window.URL.createObjectURL(file);

waveform.setSource({ mediaUrl: url, webAudio: { audioBuffer } },
   err => { if (err) console.error(err) });

jgentes avatar Feb 23 '21 01:02 jgentes

I've just fixed setSource() to also call mediaElement.load() which hopefully solves this. Please re-open if there are still any problems.

chrisn avatar Dec 04 '22 14:12 chrisn