Code change:
3.2. <del> The first stream opened is a client-initiated bidirectional stream where the peers exchange SETUP messages (message-setup).  The subsequent streams MAY be either unidirectional or bidirectional. For exchanging content, an application would typically send a unidirectional stream containing a single OBJECT message (message- object), as putting more than one object into one stream may create head-of-line blocking delays.  However, if one object has a hard dependency on another object, putting them on the same stream could be a valid choice. </del> <ins> The first stream opened is a client-initiated bidirectional control stream where the peers exchange SETUP messages (message-setup).  All messages defined in this draft are sent on the control stream after the SETUP message.  Control messages MUST NOT be sent on any other stream, and a peer receiving a control message on a different stream closes the session as a 'Protocol Violation'.  Objects MUST NOT be sent on the control stream, and a peer receiving an Object on the control stream closes the session as a 'Protocol Violation'. This draft only specifies a single use of bidirectional streams. Objects are sent on unidirectional streams.  Because there are no other uses of bidirectional streams, a peer MAY currently close the connection if it receives a second bidirectional stream. The control stream MUST NOT be abruptly closed at the QUIC layer. Doing so results in the session being closed as a 'Protocol Violation'. </ins> 3.3.

Related discussion:
text: Control messages arrive in a specified, deterministic order. Cons: Head-of-line blocking between control messages, which sometimes may not be desired.
While I was reading the requirements draft, I found some use cases mentioning bidirectionality. Is it expected/supported that there can be data flowing in both directions (eg: a p2p call)?
Yeah, my intent is that there's a "sender" and a "receiver" per track. The ROLE param in the SETUP message indicates if an endpoint (client/server) intends to send tracks, receive tracks, or both. In the bidirectional case, both endpoints would say ROLE=BOTH. Then they could independently PUBLISH or SUBSCRIBE to tracks. Alternatively, we could say that tracks may be bidirectional... but I don't think that makes any sense.
We can simply say that data objects MUST NOT be sent over control streams, and remove any reference to whether data streams should be unidirectional or bidirectional. It doesn't matter and we can leave it to the end-points discretion.
The proposal above aligns pretty well with the idea in , more specifically this I like the separation of control stream and data streams, the latter being unidirectional streams.
I like the proposal for this. I view the HOL blocking of control messages a feature not a bug. More specifically, I think that some of our messages need to be delivered in order. Specifically if a client is trying to stop and high res video subscription and start a low res subscription, it would be good to ensure that the subscribe to the low res track does not happen until after the end the end subscription to the high res track has happened. Sending the un-subscribe then subscribe on one quic stream allows these to be sent and same time to server ( we don't need a round trip between them ) but still be delivered in order. I think it needs to be clear that multiple control messages can be outstanding at once. For example can send multiple subscribes before getting the response to the first subscribe.
I would like to write up a PR based on the above ( basically resurrecting ) that pertains to the control channels.
I like the idea of seperation of control stream and data stream.
WG is ok with a single stream, with no critical use cases for multiple. A single stream makes it easier to change bitrates 'atomically'.