admin管理员组

文章数量:1336613

I'm building a ponent that shows information about a video's audio. I use the AudioContext interface to get audio samples from a HTML5 video element. It works fine the first time I create the ponent, but when the ponent is unmounted and then recreated at a later point, I get the following error message:

Uncaught InvalidStateError: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode.

Here's how I get the audio:

const video = document.querySelectorAll('video')[0]

if (!window.audioContext) {
  window.audioContext = new (window.AudioContext || window.webkitAudioContext)
}

if (!this.source && !this.scriptNode) {
  this.source = window.audioContext.createMediaElementSource(video)
  this.scriptNode = window.audioContext.createScriptProcessor(4096, 1, 1)
}

this.scriptNode.onaudioprocess = (evt) => {
 // Processing audio works fine...
}

this.source.connect(this.scriptNode)
this.scriptNode.connect(window.audioContext.destination)

And when the ponent is unmounted I do:

if (this.source && this.scriptNode) {
  this.source.disconnect(this.scriptNode)
  this.scriptNode.disconnect(window.audioContext.destination)
}

I thought this would put me in a state where I can safely create and connect new nodes. But the next time the ponent is mounted, this block throws the error mentioned earlier:

if (!this.source && !this.scriptNode) {
  this.source = window.audioContext.createMediaElementSource(video) // this throws the error
  this.scriptNode = window.audioContext.createScriptProcessor(4096, 1, 1)
}

I could get it to work by making everything global, i.e. putting source and scriptNode on window rather than this. But that won't work if my video element changes. What's the correct way to do this?

I'm building a ponent that shows information about a video's audio. I use the AudioContext interface to get audio samples from a HTML5 video element. It works fine the first time I create the ponent, but when the ponent is unmounted and then recreated at a later point, I get the following error message:

Uncaught InvalidStateError: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode.

Here's how I get the audio:

const video = document.querySelectorAll('video')[0]

if (!window.audioContext) {
  window.audioContext = new (window.AudioContext || window.webkitAudioContext)
}

if (!this.source && !this.scriptNode) {
  this.source = window.audioContext.createMediaElementSource(video)
  this.scriptNode = window.audioContext.createScriptProcessor(4096, 1, 1)
}

this.scriptNode.onaudioprocess = (evt) => {
 // Processing audio works fine...
}

this.source.connect(this.scriptNode)
this.scriptNode.connect(window.audioContext.destination)

And when the ponent is unmounted I do:

if (this.source && this.scriptNode) {
  this.source.disconnect(this.scriptNode)
  this.scriptNode.disconnect(window.audioContext.destination)
}

I thought this would put me in a state where I can safely create and connect new nodes. But the next time the ponent is mounted, this block throws the error mentioned earlier:

if (!this.source && !this.scriptNode) {
  this.source = window.audioContext.createMediaElementSource(video) // this throws the error
  this.scriptNode = window.audioContext.createScriptProcessor(4096, 1, 1)
}

I could get it to work by making everything global, i.e. putting source and scriptNode on window rather than this. But that won't work if my video element changes. What's the correct way to do this?

Share asked Jul 19, 2016 at 14:11 tobiasandersentobiasandersen 8,6883 gold badges31 silver badges40 bronze badges 1
  • Did you get around this one, by chance? I'm facing the exact same problem and still haven't found a solution. – spoutnik Commented Jul 10, 2019 at 17:26
Add a ment  | 

1 Answer 1

Reset to default 3

You're not destroying the node you created with context.createMediaSourceElement. You have your on page video element which hasn't changed, all you've done is disconnected the video audio stream from your audio graph. Therefore the video element is still bound to an AudioNode, in this case 'this.source'. Instead of trying to recreate source just detect if the source is already defined.

if (this.source == undefined) {
  // Build element
  this.source = window.audioContext.createMediaElementSource(video);
}

this.scriptNode = window.audioContext.createScriptProcessor(4096, 1, 1)
this.source.connect(this.scriptNode);
this.scriptNode.connect(window.audioContext.destination);

本文标签: javascriptProblems disconnecting nodes with AudioContext (Web Audio API)Stack Overflow