Bug 17795 - Behavior of multiple connections to same node needs to be explicitly defined
Behavior of multiple connections to same node needs to be explicitly defined
Status: CLOSED FIXED
Product: AudioWG - OBSOLETE - Moved to Github
Classification: Unclassified
Component: Web Audio API - OBSOLETE - See Github
unspecified
All All
: P2 minor
: TBD
Assigned To: Chris Rogers
public-audio
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-07-17 18:40 UTC by Chris Wilson
Modified: 2014-10-28 17:17 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Wilson 2012-07-17 18:40:12 UTC
I noticed that the spec doesn't say what should happen when you multiply connect() a node to another node, e.g.

nodeA.connect( nodeB );
nodeA.connect( nodeB );

Given the fan-out/sum-in model, it *could* be expected you could have multiple independent connections.  The current Chrome behavior is that the second line above is a no-op; I prefer this behavior, but it needs to be explicitly stated in the AudioNode.connect() description.


Suggested text:

There can only be one connection between a given output of one specific node and a given input of another specific node; multiple connections with the same termini are ignored.  For example, 

nodeA.connect( nodeB );
nodeA.connect( nodeB );

will have the same effect as

nodeA.connect( nodeB );
Comment 1 Robert O'Callahan (Mozilla) 2012-07-19 05:07:19 UTC
This seems like an arbitrary limitation. It would be simpler for connect() to always create a new connection than for connect() to sometimes not create a new connection. What's the motivation for making the second connect() a no-op?
Comment 2 Chris Wilson 2012-07-19 15:24:50 UTC
If you allow multiple connections between two nodes*, then you'll have to provide an identifier for that connection, and enable the disconnect() to take that identifier (and require developers to hang on to that identifier).  Or, said another way - if connect() always adds another connection, even if it already exists, then what does disconnect() do, and how do you know when you are really disconnected?  It seems like enabling multiple connections would complexify the connect/disconnect part of the API significantly.

If there's a scenario for making multiple connections between two nodes*, I'm open to hearing it; I just couldn't think of any.  I would presume it would just effectively double the gain, which of course is easy to do in other ways.

*Technically, these should both read "the same input/output pair of two nodes."  Of course you can make connections between different i/o pairs.
Comment 3 Robert O'Callahan (Mozilla) 2012-07-19 15:41:15 UTC
(In reply to comment #2)
> If you allow multiple connections between two nodes*, then you'll have to
> provide an identifier for that connection, and enable the disconnect() to take
> that identifier (and require developers to hang on to that identifier).  Or,
> said another way - if connect() always adds another connection, even if it
> already exists, then what does disconnect() do, and how do you know when you
> are really disconnected?

disconnect() could just remove one of the connections.

(I do think having identifiers for connections is a good idea though. MSP has them --- InputPorts --- and it lets you set parameters on connections, which seems useful.)

> If there's a scenario for making multiple connections between two nodes*, I'm
> open to hearing it; I just couldn't think of any.  I would presume it would
> just effectively double the gain, which of course is easy to do in other ways.

The API should behave predictably even when used in unexpected ways, even ways that aren't the best approach to any given use-case.

Imagine if some module builds an AudioNode A, and then two other modules independently get hold of A and try to play it by connecting it to the DestinationNode. It would be confusing to have one of those operations unexpectedly fail.
Comment 4 Chris Wilson 2012-07-19 16:17:43 UTC
(In reply to comment #3)

> disconnect() could just remove one of the connections.

I would expect.  But we'd have to alter the API to return the number of existing connections, or something, to tell if the nodes are still connected.  (So you'd have some way of saying "REALLY disconnect these nodes".)

> (I do think having identifiers for connections is a good idea though. MSP has
> them --- InputPorts --- and it lets you set parameters on connections, which
> seems useful.)

I'm not fundamentally opposed to the idea, but I think the API should be usable in most cases without having to keep track of those identifiers.

> > If there's a scenario for making multiple connections between two nodes*, I'm
> > open to hearing it; I just couldn't think of any.  I would presume it would
> > just effectively double the gain, which of course is easy to do in other ways.
> 
> The API should behave predictably even when used in unexpected ways, even ways
> that aren't the best approach to any given use-case.

The API *IS* predictable.  All I was saying is that the behavior needs to be explicit in the spec.

> Imagine if some module builds an AudioNode A, and then two other modules
> independently get hold of A and try to play it by connecting it to the
> DestinationNode. It would be confusing to have one of those operations
> unexpectedly fail.

I'm not suggesting at all that it WOULD fail.  It doesn't today - it just doesn't create an ADDITIONAL, duplicate connection (thereby doubling the gain, which would be just as unpredictable, and IMO less usable.)
Comment 5 Robert O'Callahan (Mozilla) 2012-07-19 16:37:30 UTC
> > Imagine if some module builds an AudioNode A, and then two other modules
> > independently get hold of A and try to play it by connecting it to the
> > DestinationNode. It would be confusing to have one of those operations
> > unexpectedly fail.
> 
> I'm not suggesting at all that it WOULD fail.  It doesn't today - it just
> doesn't create an ADDITIONAL, duplicate connection (thereby doubling the gain,
> which would be just as unpredictable, and IMO less usable.)

Depends on your point of view I guess. In this case I think the author would expect connect() to cause a change in the output, and it won't.
Comment 6 Chris Wilson 2012-07-19 16:48:51 UTC
(In reply to comment #5)
> Depends on your point of view I guess. In this case I think the author would
> expect connect() to cause a change in the output, and it won't.

I guess I translate connect() as "make sure these nodes are connected".  I see the model you're describing, and it's consistent; I think we just need to choose the simplicity of the model (no identifiers) vs the utility of multiple connections between node i/o points.
Comment 7 Chris Rogers 2012-07-30 20:30:47 UTC
My view is that connecting the same thing twice to another thing will *not* create a duplicate connection since the connection has already been made.  Think about this in the real world - what does it mean if I plug my guitar into my guitar amp with a cable - then plug it in *again* to the exact same amp input with another different cable!  I'm quite certain developers won't be confused by this, because I think it's an anomaly and doing nothing will be exactly what they expect.  We will need to add more details to the spec explaining this...
Comment 8 Robert O'Callahan (Mozilla) 2012-07-30 21:42:03 UTC
(In reply to comment #7)
> Think about this in the real world - what does it mean if I plug my guitar into
> my guitar amp with a cable - then plug it in *again* to the exact same amp
> input with another different cable!

Presumably it's just like plugging in another guitar which happens to be producing the same output as the first one.

> I'm quite certain developers won't be
> confused by this, because I think it's an anomaly and doing nothing will be
> exactly what they expect.

The real world doesn't have code modularity and first-class node objects that can be passed around and shared through arbitrary control and data flow. I suspect in the real world you don't shout "here's the output of my guitar, do what you want with it" and throw a lead over to someone on the other side of a crowded room you haven't ever met (who then shares it with several of her friends).

We're not building guitars and amps, we're building software APIs. These APIs will be used by thousands of people who have never plugged a guitar into an amp. They will not limit themselves to using Web Audio to simulate "real world" artifacts.
Comment 9 Tony Ross [MSFT] 2012-07-31 23:23:43 UTC
The "do nothing" behavior for duplicate calls to connect() is also consistent with other DOM APIs like addEventListener (which silently ignores duplicate registrations). As such, I think it's a reasonable approach for this scenario.
Comment 10 Robert O'Callahan (Mozilla) 2012-07-31 23:43:16 UTC
That's an interesting point. However, the addEventListener behavior is also bad. It means

var f = function() { alert("hello"); };
for (var i = 0; i < 2; ++i) {
  document.documentElement.addEventListener("click", f, false);
}

behaves differently from

for (var i = 0; i < 2; ++i) {
  document.documentElement.addEventListener("click", function() { alert("hello"); }, false);
}

and

  document.documentElement.addEventListener("click", f, false);
  document.documentElement.removeEventListener("click", f, false);
  document.documentElement.addEventListener("click", f, false);

behaves differently from

  document.documentElement.addEventListener("click", f, false);
  document.documentElement.addEventListener("click", f, false);
  document.documentElement.removeEventListener("click", f, false);

I don't think being consistent with badness is a good thing.
Comment 11 Chris Rogers 2012-10-09 22:03:27 UTC
Fixed:
https://dvcs.w3.org/hg/audio/rev/351b64e571ba
Comment 12 Chris Wilson 2012-10-09 22:06:14 UTC
Looks good to me.
Comment 13 Olivier Thereaux 2014-10-28 17:17:54 UTC
Closing. See https://github.com/WebAudio/web-audio-api/issues for up to date list of issues for the Web Audio API.