2019年12月18日水曜日

ラズベリーパイでradikoラジオをつくる: その8 AirPlayストリーミング

shairport-syncをインストール

タイトルとは矛盾しますが、外部入力くらい付けても良いよね、ということでAppleのAirPlay対応を試してみることにしました。これは、iPhoneやitunesからWi-Fi接続のスピーカに見えるというものです。shairport-syncが有名で、様々なサイトで紹介されています。何をやっているのかよくわかりませんので、手順のみ列挙します。

必要なパッケージをインストール
$ sudo apt-get update
$ sudo apt-get install -y build-essential git xmltoman autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev
gitからshairport-syncをクローンしてビルド。
$ git clone https://github.com/mikebrady/shairport-sync.git
$ cd shairport-sync
$ autoreconf -i -f   ・・・数分かかります
$ ./configure --sysconfdir=/etc --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemd
$ make
$ sudo make install
shairport-syncの自動起動を設定
$ sudo systemctl enable shairport-sync

shairport-sync.conf を編集します。設定項目がコメントアウトされているので、適宜修正して有効にします。
$ sudo nano /etc/shairport-sync.conf
general = {
name = "IP Radio Receiver";
//interpolation = "soxr";
ignore_volume_control = "yes";
nameは、iPhone等に表示されるデバイス名です。interpolationは、サンプルレート変換に使用するソフトウエアで soxr は処理が重い代わりに音質が良いとされています。私は有効にせず、デフォルトの basic で行くことにしました。ignore_volume_control = "yes"で iPhone等でのボリューム設定を無視します。

shairport-syncサービスを起動
$ sudo systemctl start shairport-sync
systemctl のステータスを表示
$ sudo systemctl status shairport-sync

iTunesから鳴らしてみる

アプリの上部のアイコンをクリックすると、IP Radio Receiverが表示されました。レ点を入れ、再生するとRadiko音声とミックスされて音楽が聞こえてきます。iPadからもあっさりと動作してくれて拍子抜けでしたね。
iTunesの再生ボタンを押してから音が出るまで2秒ほど遅延があります。Wi-Fiの品質にシビアのようで、弱電界では途切れたり再生が停止してしまします。ラズパイのWi-Fiは2.4GHzなので混信の影響も大きいのだろうと考えています。



2019年12月14日土曜日

ラズベリーパイでradikoラジオをつくる: その7 radikoの再生停止問題

スピーカを接続

Auratoneに接続してみました。スピーカのエッジはぼろぼろなのに、まともな音で鳴ってくれます。エッジ交換したら良くなるんですかね。初めて使ったD級パワーアンプ、好印象です。


radiko再生停止問題

radikoを起動後1分ほどで再生が停止、手動でもういちど再生するとその後は安定するという現象がありましたが。この開発を進めるうち、いつの間にやら再生開始から1分ほどで停止するのを繰り返すようになってしまいました。苦し紛れで、自動的に再接続する仕組みを実装しましたけど、1分毎に10秒以上無音になるようでは、最早使い物になりません。調べてみたところ、mplayer のキャッシュを設定すれば改善できるという情報があり早速試したところ解決することができました。

mplayer の設定は、/etc/mplayer/mplayer.conf にあります。こんな内容です。
# Use 8MB input cache by default.
#cache = 8192
#
# Prefill 20% of the cache before starting playback.
#cache-min = 20.0
mplayer.conf のデフォルトはキャッシュ無しの設定でした。そこでキャッシュを設定したところ256kBで安定して再生できることを確認しました。RadikoのPC向け配信ビットレートはHE-AAC 48kbpsということからキャッシュ256kBは約40秒に相当します。家庭内の光ファイバ環境ならこれで十分ではないでしょうか。とはいえキャッシュを増やせば、再生開始までの時間が増えてしまうはず。
  • 設定なし: 再生まで14秒、1分ほどで再生が停止
  • cache = 256 :再生まで14秒、その後も途切れない
  • cache = 512 :再生まで16秒、その後も途切れない
以上の結果から、256kBが妥当と考えました。cache-minは、0から20まで変えてみましたが、再生開始までの時間に大きな変化はありません。光回線の速度が十分に速いためでしょう。ところで再生まで14秒とは、時間かかりすぎです。以前は10秒程度だったはず。ラジコプレミアム対応のスクリプトをコマンドで手動実行して時間を測ってみました。

  • 初回: 13秒
  • 2回目以降: 8秒
初回よりも2回目以降はより早く再生開始します。これは認証情報を使い回しているからと考えています。この初回時の時間と、操作ボタンでの再生開始までの時間は、ほぼ一致します。ということは、操作ボタンでは初回扱いとして動作しているに違いありません。Pythonのsubprocess.Popen()でスクリプトを起動しているせいかなあ。

ところで、開発を進めるうちに再生停止が顕在化する原因がわかりました。なんと、操作スクリプトがCPU使用率を圧迫していたのです。python /home/pi/operation_panel/panel.pyというのがそれで63.8%もあります。radikoの再生をしている mplayer と合わせてCPU使用率 90%弱とほぼ目一杯使い切っています。


操作スクリプトがそんなに重いのは不自然です。とりあえず、対症療法でwaitを入れると、10%程に下がりました。それでもSSHログインやpsコマンドを打ち込むだけでも一瞬音が途切れます。操作スクリプトの見直しが必要ですね。


2019年12月10日火曜日

ラズベリーパイでradikoラジオをつくる: その6 Wi-Fiを自動切替・信号強度表示

登録済みのWi-Fiを自動的に切り替え

自宅や外出先で使用することを想定して、Wi-Fiの自動切り替えを設定してみます。
まずは、wpa_supplicant.confにアクセスポイントを設定を追加して行きます。
$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
 次のように、3つのアクセスポイントを設定してみました。関連する設定を抜粋して示します。ssidはSSID名、pskはパスフレーズ、priorityは接続優先度で、値が大きいssidに優先的に接続します。なお、パスフレーズの暗号化やSSIDのステルス機能を使うには更に設定が必要です。
network={
ssid="aterm-00000"
psk="abcd0000"
priority=2
}
network={
ssid="MOBILErouter"
psk="abcd1111"
priority=3
}
network={
ssid="Android1234"
psk="abcd2222"
priority=1
}
さらにIPアドレスを固定する場合は dhcpcd.conf を設定します。
$ sudo nano /etc/dhcpcd.conf
IPアドレスを固定したいアクセスポイントのみ次のように記載します。モバイルルータやスマホのテザリングでは自動割り当てにしたいので何も記載しません。
interface wlan0
ssid aterm-00000
static ip_address=192.168.0.100/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1

Wi-Fi IPアドレス表示

Linuxの「ip」コマンドでwlan0の情報を取得しました。
$ ip addr show dev wlan0
2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.100/24 brd 192.168.0.255 scope global noprefixroute wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::6f54:0000:0000:0000/64 scope link
       valid_lft forever preferred_lft forever
さらにawkでIPアドレスを抽出します
$ ip addr show dev wlan0 | awk '/inet /{printf substr($2, 1, index($2, \"/\")-1)}'
192.168.0.100
ところで、ipコマンドで送受信バイト数が表示出来ますから、この数値を使ってリアルタイムのデータ転送速度を表示出来そうです。
$ ip -s link show dev wlan0
2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DORMANT group default qlen 1000
    link/ether b8:27:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast 
    1935131    3444     0       0       0       1527 
    TX: bytes  packets  errors  dropped carrier collsns
    177144     1401     0       0       0       0   
   

Wi-Fi 信号強度とSSID表示

Linuxの「iwconfig」コマンドを利用します。
$ iwconfig wlan0
wlan0     IEEE 802.11  ESSID:"aterm-00000" 
          Mode:Managed  Frequency:2.442 GHz  Access Point: 00:3A:9D:91:D3:94 
          Bit Rate=65 Mb/s   Tx-Power=31 dBm 
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
          Link Quality=70/70  Signal level=-38 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:1  Invalid misc:0   Missed beacon:0
信号強度、ESSIDもawkで抽出します。ESSIDは二重引用符で囲まれたものを抽出したかったのですが、苦し紛れで文字数数えています。
$ iwconfig wlan0 | awk '/Signal level/{print substr($4,7)}'
$ iwconfig wlan0 | awk '/ESSID/{printf substr($NF, 8, length($NF)-8)}'

Wi-Fi 信号強度インジケータの実装

スマホの真似をしようとしたんですが、表示の閾値をいくつにするか悩みました。通信品質はWi-Fiの変調方式はもちろん、機器の差や近隣の干渉波によっても変わるはず。Webで調べるとバッファローは「-30dBm~-40dBmで無線接続が安定します」、IBS JapanのページにはVoIPの最小信号強度-67dBmとありました。これらを参考に、-60dBm/-50dBm/-40dBmでインジケータを振らすことにしました。