title: Transferring a Readable Stream from one browser tab to another in Chrome
body: <p>I have looked into a few approaches to transfer a readable stream from one tab in Chrome to another:</p>
  <ol>
  <li>Broadcast channel -- doesn't support transferrable objects in postMessage</li>
  <li>Sender window postMessages to a Shared Worker connected to the sender and receiver windows. Shared Worker then postMessages to the receiver window.</li>
  </ol>
  <p>From all of the documentation I have read, option 2 should work. However, my proof of concept fails with &quot;DOMException: chunk could not be cloned&quot; when I try to call the <a href="https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/pipeTo" rel="nofollow noreferrer"><code>pipeTo</code></a> method on the readable stream received by the receiver window.</p>
  <p>I suspect this is because there is an issue transferring a stream's data through an intermediary (the Shared Worker) to a final destination. When I perform the same steps below with an empty, <code>new ReadableStream()</code>, there is no DOMException, which leads to the conclusion that the process of transferring data in the stream is the source of the error. I am not sure if there is a way around this. I can't transform the readable stream within the shared worker because that will lock it, and locked streams cannot be transferred.</p>
  <p>Note that my example uses a media stream to generate data on the readable stream. My particular use case is related to transferring audio between same-origin tabs, however I am trying to make this question generic to maximize its utility to others. Also, I am aware that <a href="https://github.com/w3c/mediacapture-extensions/pull/24" rel="nofollow noreferrer">MediaStreamTracks are now transferable via a new w3c standard</a>, but no browsers support this as far as I am aware.</p>
  <p>Example code:</p>
  <pre><code>//client.js
  var myWorker = new SharedWorker(&quot;worker.js&quot;);
  myWorker.port.onmessage = async (e) =&gt; {
      console.log(e);
      if (e.data === 'Trigger Transfer') {
          navigator.mediaDevices.getUserMedia({audio:true})
              .then(function(stream) {
                  const audioTrack = stream.getAudioTracks()[0];
                  const trackProcessor = new MediaStreamTrackProcessor({ track: audioTrack });
                  const readable = trackProcessor.readable;
                  console.log(&quot;here&quot;);
                  myWorker.port.postMessage(readable, [readable]);
              })
              .catch(function(err) {
                  console.log(&quot;Failed to get user media&quot;, err);
              });
      }
      else {
              if (e.data instanceof ReadableStream) {
              try {
                  console.log(e.data.locked === false); //This prints true. Locking does not appear to be the problem.
                  await e.data.pipeTo(new WritableStream()); //This line leads to &quot;DOMException: chunk could not be cloned&quot;
              } catch(e) {
                  console.log(e);
              }
          }
      }
  };
  </code></pre>
  <pre><code>//shared-worker.js
  onconnect = function(e) {
    var port = e.ports[0];
    setTimeout(()=&gt;{
      port.postMessage(&quot;Trigger Transfer&quot;);
    }, 500);
    port.onmessage = function(e) {
      port.postMessage(e.data, [e.data]);
    }
  }
  </code></pre>