WebRTC Native Client Momo の test モードと Ayame Web SDK で通信してみる

## 環境

- Momo
    - https://github.com/shiguredo/momo
    - `momo-2020.8.1_raspberry-pi-os_armv6`
    - Raspberry Pi Zero
- Ayame
    - https://github.com/OpenAyame/ayame-web-sdk
    - `@open-ayame/ayame-web-sdk@2020.3.0`
    - Google Chrome

## 動機

Raspberry Pi のカメラで撮った映像を Momo を使って PC に送り、そこに JavaScript で色々手を加えたかったのですが、test モードで出てくる HTML と JS が結構いじりにくいものだったので、Ayame でなんとかできないかと試行錯誤したものです。

[Momo 2020.6 のリリース](https://github.com/shiguredo/momo/releases/tag/2020.6) で test モードと ayame モードの相互接続が可能であることが言われていたり、Discord 上でも Ayame 互換であるようなことが言われていたりしますが、Ayame Web SDK による利用について何も情報がないので記しておきます。

## 仕様の確認

Momo が test モードで動いたときに配信される HTML と JS は [/html](https://github.com/shiguredo/momo/tree/develop/html) 以下のものです。

これと [ayame-web-sdk](https://github.com/OpenAyame/ayame-web-sdk) および [Ayame の仕様書](https://github.com/OpenAyame/ayame/blob/develop/docs/SPEC.md) を見比べることで、なんとなく何が違うのかを探ることができます。

正直細かいところまではわかりませんでしたが、おそらく Ayame のプロトコルの register/accept 部分を除いてそれ以降は test モードと同じ動作をしているように見えます。ということで、エンドポイントは `ws://[Raspberry Pi の IP アドレス]:8080/ws` とし、`roomId` は空でも良いようです。

## コード

https://github.com/OpenAyame/ayame-web-sdk-samples/blob/master/recvonly.html を参考にします。

```html
<button id="connect-button"></button>
<button id="disconnect-button"></button>
<video id="remote-video"></video>
```

```js
const remoteVideo = document.getElementById('remote-video');
const connectButton = document.getElementById('connect-button');
const disconnectButton = document.getElementById('disconnect-button');

const conn = Ayame.connection('ws://raspberrypi.local:8080/ws', '', {
  ...Ayame.defaultOptions,
  audio: { enabled: false },
  video: { direction: 'recvonly', enabled: true, codec: 'H264' },
});
conn.on('open', (e) => {
  console.log('open', e);
});
conn.on('disconnect', (e) => {
  console.log('disconnect', e);
});
conn.on('addstream', (e) => {
  console.log('addstream', e);
  remoteVideo.srcObject = e.stream;
  remoteVideo.play();
});

connectButton.addEventListener('click', () => {
  conn.connect(null);
});
disconnectButton.addEventListener('click', () => {
  conn.disconnect();
});
```

```bash
$ ./momo --no-audio-device --use-native --force-i420 test
```

## 動作結果

やってみたら案外ちゃんと動きました。

ただ、Connect ボタンを押してから動画が表示されるまでの時間が、test モードで出てくるページでは1秒以内に収まるのに対し、上のものを使うとたまに3秒程度かかることがありました。（ページを PC 側のローカルサーバではなく Raspberry Pi から配信するようにしたらこれがなくなったので、ページの置き場所による？）

## データチャンネルも使ってみる

https://github.com/OpenAyame/ayame-web-sdk-samples/blob/master/datachannel.html を参考にします。

test モードにおけるラベルは `serial` になっていますが、他のもので試しても動いたので何でも良いようです。

```js
const remoteVideo = document.getElementById('remote-video');
const connectButton = document.getElementById('connect-button');
const disconnectButton = document.getElementById('disconnect-button');

const conn = Ayame.connection('ws://raspberrypi.local:8080/ws', '', {
  ...Ayame.defaultOptions,
  audio: { enabled: false },
  video: { direction: 'recvonly', enabled: true, codec: 'H264' },
});

let dataChannel = null;
const sendData = (data) => {
  if (dataChannel && dataChannel.readyState === 'open') {
    dataChannel.send(data);
  }
};
const onMessage = (e) => {
  console.log(new TextDecoder().decode(e.data));
};

conn.on('open', async (e) => {
  console.log('open', e);
  dataChannel = await conn.createDataChannel('serial');
  if (dataChannel) {
    dataChannel.onmessage = onMessage;
  }
});
conn.on('datachannel', (channel) => {
  if (!dataChannel) {
    dataChannel = channel;
    dataChannel.onmessage = onMessage;
  }
});
conn.on('disconnect', (e) => {
  console.log('disconnect', e);
  dataChannel = null;
});
conn.on('addstream', (e) => {
  console.log('addstream', e);
  remoteVideo.srcObject = e.stream;
  remoteVideo.play();
});

connectButton.addEventListener('click', () => {
  conn.connect(null);
});
disconnectButton.addEventListener('click', () => {
  conn.disconnect();
});
```

```bash
$ socat -d -d pty,raw,echo=0 pty,raw,echo=0
> 2020/10/12 16:36:51 socat[1017] N PTY is /dev/pts/1
> 2020/10/12 16:36:51 socat[1017] N PTY is /dev/pts/2
> 2020/10/12 16:36:51 socat[1017] N starting data transfer loop with FDs [5,5] and [7,7]
```

```bash
$ ./momo --no-audio-device --use-native --force-i420 --serial /dev/pts/1,9600 test
```

## 動作結果
こちらも送受信ともにちゃんと動作しました。