2020年4月29日水曜日

ラズベリーパイでradikoラジオをつくる: その13 基板を再作成



前回作成した基板は、スイッチの高さが不揃いだったので基板を再作成しました。ついでに、当時国内版が発売されたばかりのラズパイ3A+対応とその他の改良を盛り込みました。

・プッシュスイッチをオムロンからAPEMに変更
・Raspberry Pi 3 Model A+を搭載できるようスーパーキャパシタ品の位置を変更
・ロータリエンコーダを基板取付形/スイッチ付きに変更
・チャタリング防止用のコンデンサ追加
・スーパーキャパシタのUVLO用パワースイッチを省略
・電源のオフディレイタイマー設定のジャンパピンを省略
・オーディオD/Aコンバータのミューティング回路接続を省略
・フォーンジャックの品種を変更
・試験用UART接続ピンの引き出し
・その他、細かな修正

回路図も変更になっています。



ただ1点、課題が残りました。
3台製作したうちの1台でスピーカ出力がプツプツと途切れることがありました。まるでデジタルアンプPAM8304が誤動作してシャットダウンを繰り返しているかのようです。しかもそれは基板ごとの個体差があること、USB ACアダプタの電源電圧が高めの場合に影響があることがわかっています。それでも、いろいろ手を尽くしてみたのですが、どうにもよくわかりません。仕方なく対症療法としてPAM8304を交換したり、USB ACアダプタを選別することで対応することにしました。

2020年4月26日日曜日

ラズベリーパイでradikoラジオをつくる: その12 HLS形式に対応するradiko受信スクリプト

radikoウェブサイトに『Adobe Flash サポート終了』と衝撃的なお知らせが出ていました。受信スクリプトはまさにFlash形式を使用していますので、後継となるHLS形式に否応なく移行する必要が出てきました。


HLS対応のスクリプトはWeb上でいくつか発表されています。その中でも、エリアフリー対応で単一のファイルで構成されている radish を選定しました。radish は、NHKラジオ らじる★らじるやListenRadio等で現在配信中の番組を保存するシェルスクリプトです。
まずは、radishの実行に必要なアプリをインストールします。
$ sudo apt install libxml2-utils
$ sudo apt install ffmpeg
$ sudo apt install jq

次に、GitHubからダウンロードしたスクリプトファイル radi.sh を/home/pi/radikoに置き、スクリプトの録音ルーチンを再生できるように書き替えます。(赤字部分)
# Record
if [ "${type}" = "radiko" ]; then
   ffplay \
      -nodisp -loglevel quiet \
      -headers "X-RADIKO-AUTHTOKEN:${radiko_authtoken}" \
      -i ${playlist_uri}

elif [ "${type}" = "shiburadi" ]; then
   ffplay \
      -nodisp -loglevel quiet \
      -i ${playlist_uri}

else
   ffplay \
      -nodisp -loglevel quiet \
      -i ${playlist_uri}

fi

このスクリプトの使い方は次の通りです。
radikoで地元局(この例ではTBSラジオ)を受信する場合
$ cd ~/radiko/
$ ./radi.sh -t radiko -s TBS
radikoプレミアムのログイン情報を付加するとエリアフリー受信ができます。次の例では、北海道のHBCラジオをエリア外で受信します。
$ ./radi.sh -t radiko -s HBC -i “taro@mail.jp” -p “password”
NHKらじる☆らじる にも対応しています。NHKはエリア制限が無いようで、エリア外からでも受信できました。
$ ./radi.sh -t nhk -s tokyo-r1
赤字で示した放送局IDやメディア記号は、次のコマンドで知ることができます。(radishはシンプルなのに多機能です!)
$ ./radi.sh -l
ところで、再生にmplayerを使う場合、スクリプトの実行開始から放送の聴こえ始めまで10秒程度かかりますが、ffplayでは2秒程度です。しかも音切れもなく安定しており言うことがありません。素晴らしい!

2020年4月24日金曜日

ラズベリーパイでradikoラジオをつくる: その11 Wi-Fi設定をパネル操作で行う

Wi-Fiやradikoエリアフリーなど各種の設定をパネルスイッチ操作で行えるようにしてみました。以下にサンプル画面を示します。地味な画面ながらプログラミングはとっても手間がかかりました。


Wi-Fi設定
一筋縄で行かなかったのはWi-Fiの切替でした。当初、nmcliコマンドを使おうとしましたが、思うように動いてくれないところがあり、結局 wpa_supplicant.conf の書き換えで対応しました。
処理の流れとしては、1アクセスポイント探索、2接続先を選択、3パスフレーズ入力、4アクセスポイント接続とステップを踏んでいきます。

まずscanコマンドでアクセスポイント探索を開始します
$ sudo wpa_cli -i wlan0 scan
そして結果が得られるまで scan_resultsがOKを返すのを待ちます。Raspberry Pi 3A+で5秒ほどかかります。
$ sudo wpa_cli -i wlan0 scan_results

scan結果を画面に表示させたところです。現在接続中のアクセスポイントを赤字で表しています。さらに、近隣のアクセスポイントも表示され、なかなか興味深いです。

接続したいアクセスポイントにカーソルを合わせて選択すると、Wi-Fiパスワードの入力画面を表示します。

選択したアクセスポイントとパスワードをwpa_supplicant.confに書き込み、wpa_cliコマンドにより再読込すると設定変更が反映されます。コマンド発行後、しばらくすると新たにDHCPサーバからIPアドレスが付与されインターネット通信が有効になります。
$ sudo wpa_cli -i wlan0 reconfigure
これらの設定画面により、PCに接続することなく自宅Wi-Fiや携帯テザリングなどの切り替えを自由にできるようになりました。

radiko設定
放送局プリセットは全県分を作成しました。エリア選択画面をもうけ、県別の放送局プリセットを選べます。radikoのエリアフリーのログイン情報を登録すれば、各県の放送局を自由に選んで聴くことができます。


2020年4月17日金曜日

ラズベリーパイでradikoラジオをつくる: その10 AirPlayのジャケ写画像を表示


前回記事から日にちがたってしまいました。当時困ったことを思い出しながら書き残しておきます。shairport-sync-metadata-readerで取得した楽曲情報をLCD表示を行うには、メタデータ受信とLCD表示を並列処理する必要があり、まさかの"マルチスレッドプログラミング"となりました。別スレッドで受信したメタデータをPython 2.7Queueクラスに入れ、メインプログラムで逐次それぞ取り出す処理をしました。
スレッドの起動は次のような感じです。ひとつ問題があって、手動でPythonスクリプトを起動すると期待通り動作するのに、Linuxの自動起動に組み込んだらNGという現象がありました。どうやらshairport-syncよりメタデータ受信のスレッドが先行して起動してしまっていたらしく、shairport-syncプロセス起動を待って、スレッドを起動するようにすると期待通りの動作になりました。

import threading
if get_shairport_status() == 'active':
    if threading.active_count() == 1:
        thread_1 = threading.Thread(target=airplay.read)
        thread_1.start()

ジャケ写画像の表示は、PILpillow)ライブラリのおかげで簡素に書けました。他人のライブラリを拝借しているだけでなんですが、画像が表示されるとそれなりに達成感を感じられました。スクリプトを抜粋すると、つぎのような感じです。LCDへのデータ転送がとにかく遅いので、画像に限らず描画範囲を必要最小限にするよう心がけないと、すぐレスポンスが悪くなります。

path = coverart_path + "/" + coverart_filename
im = Image.open(path)
im = im.resize((140, 140))
im = im.rotate(90)
disp.buffer.paste(im, (75, 179))
disp.set_window(x0=75, y0=170, x1=220, y1=319)
disp.display()

あと、日本語表示をするためIPAフォントをインストールし、文字コード関連の記述を追記することになります。
font2gothic = ImageFont.truetype('ipag.ttf', 18, encoding='unic')
str = airplay.artist
str = trim_str(str.decode('utf-8'), 18)
draw_rotated_text(disp.buffer, str, (109, 2), 90, font2gothic, fill=col_orange)
使用した液晶パネルの都合で、デフォルトでは文字が半回転した右詰め表示になっていまいます。所定の表示幅に合わせて文字を左詰めするいは、余ったスペースを半角スペース埋めにしようとしたところ都合のよい関数がなくて、無理矢理つくりました。等幅フォントを前提としています。

# 全角は2文字として計数し、半角n個の文字列を切り出し
    def trim_str(self, text, n):
        bytes_count = 0
        str_count = 0
        for c in text:
            if unicodedata.east_asian_width(c) in 'FWA':
                bytes_count += 2
            else:
                bytes_count += 1
            str_count +=1
            if bytes_count > n:
                str_count -= 1
                break
        if (n - bytes_count) >0:
            return text[:str_count].ljust(n + str_count - bytes_count)
        else:
            return text[:str_count]