Re: [webrtc-pc] Creation of MediaStreamTrack from raw PCM stream; Example 18 with a JSON file instead of messaging (#2570)

@youennf 

> Signaling is out of scope but there are other resources and tutorial in the web that could help you.

The signaling portion of the Issue is solved.

After re-reading and manually performing the paste at https://github.com/fippo/paste several dozen times gather the minimal requirements.

The use case in this instance is capture and streaming of monitor devices at Chromium browser, which refuses to support capture or listing of monitor devices at Linux with `getUserMedia()` and `enumerateDevices()`, respectively.

Firefox does support capture of monitor devices at Linux.

One solution to achieve the requirement of capturing monitor device at Chromium, or at least gaining access to the device, by any means, is to perform the capture of the device at Nightly, then establish an WebRTC connection with Chromium to access the `MediaStreamTrack` and `MediaStream` created at Nightly.

The use of clipboard is not ideal. Used here to automate the procedure to the extent possible, where Chromium requires focus on the document to read and write to `navigator.clipboard`.

At Nightly set flags `dom.events.testing.asyncClipboard` and `media.navigator.permission.disabled` to `true`.

```
<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <script>
      (async _ => {
        const webrtc = new RTCPeerConnection({ sdpSemantics: 'unified-plan' });
        [
          'onsignalingstatechange',
          'oniceconnectionstatechange',
          'onicegatheringstatechange',
        ].forEach(event => webrtc.addEventListener(event, console.log));
        let sdp;
        webrtc.onicecandidate = async event => {
          console.log('candidate', event.candidate);
          if (!event.candidate) {
            sdp = webrtc.localDescription.sdp;
            if (sdp.indexOf('a=end-of-candidates') === -1) {
              sdp += 'a=end-of-candidates\r\n';
            }
            try {
              await navigator.clipboard.writeText(sdp);

              async function* readClipboard() {
                while (true) {
                  try {
                    await new Promise(resolve => setTimeout(resolve, 1000));
                    // dom.events.testing.asyncClipboard
                    // optionally dom.events.asyncClipboard.dataTransfer
                    const text = await navigator.clipboard.readText();
                    if (
                      text.replace(/[\n\s]+/g, '') !==
                      sdp.replace(/[\n\s]+/g, '')
                    ) {
                      sdp = text;
                      console.log({ sdp, text });
                      break;
                    }
                    yield text;
                  } catch (e) {
                    console.error(e);
                    throw e;
                  }
                }
              }
              for await (const text of readClipboard()) {
                console.log(text);
              }

              await webrtc.setRemoteDescription({ type: 'answer', sdp: sdp });
            } catch (e) {
              throw e;
            }
          }
        };
        try {
          // media.navigator.permission.disabled
          let stream = await navigator.mediaDevices.getUserMedia({
            audio: true,
          });
          const label = 'Monitor of Built-in Audio Analog Stereo';
          let [track] = stream.getAudioTracks();
          if (track.label !== label) {
            const device = (
              await navigator.mediaDevices.enumerateDevices()
            ).find(({ label: _ }) => label === _);
            const { deviceId } = device;
            console.log(device);
            track.stop();
            stream = await navigator.mediaDevices.getUserMedia({
              audio: { deviceId: { exact: deviceId } },
            });
            [track] = stream.getAudioTracks();
          }

          const sender = webrtc.addTransceiver(stream.getAudioTracks()[0], {
            streams: [stream],
            direction: 'sendonly',
          });
          const offer = await webrtc.createOffer();
          webrtc.setLocalDescription(offer);
        } catch (e) {
          throw e;
        }
      })().catch(console.error);
    </script>
  </body>
</html>
```
at Chromium

```
<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8" />
    <style>
      body *:not(script) {
        display: block;
      }
    </style>
  </head>
  <body>
    <button id="capture">Capture system audio</button>
    <audio id="audio" autoplay controls muted></audio>

    <script>
      const audio = document.getElementById('audio');
      const capture = document.getElementById('capture');
      ['loadedmetadata', 'play', 'playing'].forEach(event =>
        audio.addEventListener(event, console.log)
      );
      const webrtc = new RTCPeerConnection({ sdpSemantics: 'unified-plan' });
      [
        'onsignalingstatechange',
        'oniceconnectionstatechange',
        'onicegatheringstatechange',
      ].forEach(event => webrtc.addEventListener(event, console.log));

      webrtc.onicecandidate = async event => {
        if (!event.candidate) {
          let sdp = webrtc.localDescription.sdp;
          if (sdp.indexOf('a=end-of-candidates') === -1) {
            sdp += 'a=end-of-candidates\r\n';
          }
          try {
            await navigator.clipboard.writeText(sdp);
          } catch (e) {
            console.error(e);
          }
        }
      };
      webrtc.ontrack = ({ transceiver, streams: [stream] }) => {
        console.log(transceiver);
        const {
          receiver: { track },
        } = transceiver;
        track.onmute = track.onunmute = e => console.log(e);
        audio.srcObject = stream;
      };
      onfocus = async _ => {
        onfocus = null;
        try {
          const sdp = await navigator.clipboard.readText();
          console.log(sdp);
          await webrtc.setRemoteDescription({ type: 'offer', sdp });
          const answer = await webrtc.createAnswer();
          webrtc.setLocalDescription(answer);
          await navigator.clipboard.writeText();
        } catch (e) {
          console.error(e);
        }
      };
    </script>
  </body>
</html>
```

![Screenshot_2020-09-07_16-30-22](https://user-images.githubusercontent.com/4174848/92421468-7bbc9400-f12d-11ea-8616-2f1e348858ec.png)

TODO: Improve signaling method. Establish `RTCPeerConnection` on any page at Chromium.

-- 
GitHub Notification of comment by guest271314
Please view or discuss this issue at https://github.com/w3c/webrtc-pc/issues/2570#issuecomment-688550258 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Tuesday, 8 September 2020 00:15:39 UTC