🚂

ラズパイ3AとmomoでPeer to Peerのライブ配信を行う

2023/04/10に公開

ラズパイ3Aとその純正のケースを買ってみました。これを使ってコンパクトなライブ配信機器を作りました。
これは私の4台目の自宅ライブカメラです。慣れてると思って油断したらちょっとハマってしまいました。

ラズパイ3Aと純正ケース

購入したもの

  • ラズパイ3A本体
  • ラズパイ3用純正ケース
  • ラズパイ3用ヒートシンク
  • マイクロUSBケーブル
  • ACアダプタ

すでにもっていたもの

  • USBカメラ

基板上に赤と緑のLEDがありますが、ケースにいれてもそれが見えます。
また、ケースにいれたままでもマイクロSDカードの抜き差しができます。

以上の2点は当たり前のことなのですが、ラズパイゼロの純正ケースではこれらができませんでした。
ちゃんとユーザーの声を聞いて改善してくれました。

初期セットアップ

本家のこのページに沿っていけばできます。
https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up/0

素晴らしいのはラズパイ専用のSDカード書き込みアプリがあって、それを使うとWiFiのアクセスポイントの情報をホストPCに保存されているものから自動で書き込むことができるので、WiFiのパスワードを自分で打ち込む必要がないことです。

これで作成したマイクロSDカードを挿して起動したら、もうsshでリモートログインできるようになります。楽勝です。ほんと素晴らしい。

momoとayamelaboでライブ配信する

カメラの映像をWebRTCでライブ配信します。
ラズパイ上のmomoからWebブラウザにPeer to Peerで送信します。シグナリング(通信情報の交換)にはayamelaboを利用しました。
送信者と受信者は1対1になります。つまり複数の受信者に向けて配信することはできません。
自分専用のライブカメラとしてはこれ十分です。
遅延時間が小さい(数百msecのオーダー)ので、映像を見ながらカメラの角度を調整するのが楽にできます。
インターネットごしに見ることができるので、自宅に設置したカメラの映像を外出先からスマフォで見るという使い方ができます。

ラズパイ3Bと3Aの違い

今まではラズパイ3Bを使っていました。3Aは今回初めて使いました。
基板のサイズが小さくなってコネクタがいくつか省略されただけなので、ソフトはそのまま流用できるだろうとおもっていましたが、大きな違いがありました。
ラズパイ3BはRAMを1GB搭載していたのですが、3Aは512MBしかありません。
このため、設定の調整が必要になることがあります。

問題発生

最初は、ラズパイ3Bと同じ設定で、1280x720 30fps でライブ配信しようとしていたのですが、これだと配信を開始して21秒経過すると止まってしまうという現象が発生しました。10回試して10回ともこうなりました。

ログメッセージの特徴的なものはこの2つでした。

[032:486][8826] (rtcp_receiver.cc:359): OnPeriodicRttUpdate: Timeout: No increase in RTCP RR extended highest sequence number.
[039:486][8826] (rtcp_receiver.cc:357): OnPeriodicRttUpdate: Timeout: No RTCP RR received.

これをみるとパケットロスが起きているようなので、WiFiの回線状況が悪いのかと思っていました。
いろいろと調べてみたところ、この現象は今回セットアップしたラズパイ3Aでは100%再現し、今まで使っていたラズパイ3Bではまれに発生し、jetson nanoでは全く発生しないということがわかりました。
ラズパイ3AをWiFiでなくてEthernetでつないでも状況は変わらなかったので回線品質の問題ではないということがわかりました。また、WebRTCのSFUのsoralaboにつないで試すと問題が発生しなかったので、peer to peer 独特の問題であることもわかりました。

回避方法を発見

いろいろと条件を変えて試すうちに、やっとうまくいく方法を見つけました。
1280x720 30fps でmjpegのデコードにハードウェアデコーダを使用していたのですが、これを1280x720 15fpsに落として、mjpegのデコードをソフトウェアで行うようにしたら安定しました。
搭載しているRAMのサイズがラズパイ3Bの半分しかないことが影響しているのだと思われます。

私のユースケースではフレームレートが30fpsであることは必須ではなく、15fpsでも問題ないので、当面はこの設定で運用してみることにします。

実際のスクリプト

#!/bin/sh -x

ROOM_ID=your-room-id
SIGNALING_URL=wss://ayame-labo.shiguredo.app/signaling
SIGNALING_KEY=your-signaling-key-xxxx-yyyy

../current/momo --no-audio-device --log-level 2 \
	--video-device /dev/video0 --resolution 1280x720 --framerate 15 --hw-mjpeg-decoder false \
	ayame --signaling-url $SIGNALING_URL --room-id $ROOM_ID --signaling-key $SIGNALING_KEY

sleep 10

ROOM_IDSIGNALING_KEYは各自のものに置き換えてください。

これをsystemdのサービスに登録して、電源が入ったら自動で送信を始めるようにしておきます。
最後の行にsleep 10 を入れているのはなんらかのエラーになったときに次のリトライまでに少し時間を置くようにするためです。

/usr/local/lib/systemd/system/ayamelabo.service
[Unit]
Description = video streaming via ayame labo

[Service]
WorkingDirectory=/home/koba/momo/work
ExecStart = /home/koba/momo/work/ayamelabo.sh
Restart = always
Type = simple

[Install]
WantedBy = multi-user.target

受信する側は、ayamalaboのdashboardにある「シグナリングキー設定済みのサンプル」のうちの「受信のみ」のページを利用することもできますし、ayame web SDKを使って自作することもできます。

関連

https://zenn.dev/tetsu_koba/articles/323466d0c791f1

Discussion