外出先でも快適ハイレゾ音源ストリーミングしたい！

# きっかけ
現在，落ち着いてきたとはいえ，やはりまだ新型コロナウイルス(COVID-19)が騒がれていて，あまり外に出たくないですよね．外に出ると気分が滅入ってしまう気がします．
でも，いつ外出することになるかわかりませんよね．
そこで，モチベーションを高めていくため，外出時も好きな曲を聴ける環境を構築しようということになりました．

## 追記
Apple Musicがハイレゾストリーミングを値段据え置きで提供するとかいうわけわからないことになったのでもうこれ使ってません…
SoftEtherもtailscale利用で完結してしまっててもうほぼ使ってません…

# 自宅の構成
基本的には以前の記事を見ていただけるとわかりやすいと思います→ [最終的な構成](https://qiita.com/Miutaku/items/ce1efbcca2570baf4bfb#%E6%9C%80%E7%B5%82%E7%9A%84%E3%81%AA%E6%A7%8B%E6%88%90)
一応ここでも一部貼っておきますね．↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/5118d228-e57d-7ec5-875c-358213b6acda.png)

NASの中でDockerが動いています．
このDockerの中では，次の2つのコンテナでサーバが動いていて，SoftEtherVPNにレイヤ2接続時のみDAAPクライアントはホームシェアリングが使えます．

- SoftEtherVPN Server(SoftEtherVPN)
- VPN接続専用のDAAPサーバ(name: daap-VPNOnly)

※図には描いてないがDAAPサーバ(name: daap)がhostネットワークでNASから直接ローカルに出る形で動作．


また，余談ですが，AppleデバイスはOSビルトインのL2TP/IPsecVPNだとLayer3未満の通信をトンネリングしてくれないはずです．また，i(Pad)OSではVPN APIの制限でサードパーティのL2なVPNが組めません．ゆえにiOSデバイスではOpenVPN L2も使えません…
まあうちはV6プラスの関係上L2TP/IPsec使えないし，iOS/iPadOSデバイス持ってないんでどのみち関係ない話なんですが…
あ，AndroidOSでは問題なくL2なVPNが使えますよ．

# どういう仕様を考えているか
- DAAPとか何かのプロトコルを使っていい感じにストリーミングしたい！
- ↑のため，私のスマートフォン(Pixel3)でSoftEtherVPN ServerにOpenVPNでL2接続

わかりやすいように図を入れておきます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/16eb98dd-0184-af92-a57b-358a126f1e93.png)


# クライアントアプリの選定
スマホからNASの音源をストリーミングするにあたり，DAAPクライアントを使いたいところですが…Android向けのDAAPクライアントアプリがほぼ無い…
そこでDLNAを使うことにしました．DLNAであればいくらでもアプリが出てきます．
今回，選定したアプリは[Bubble UPnP](https://play.google.com/store/apps/details?id=com.bubblesoft.android.bubbleupnp&hl=ja)です．
選定した理由は次のとおりです．

- VPNネットワーク上のサーバを見つけてくれる
- アプリが落ちない
- デザインが良い
- 開発が続いている

なお，VPNクライアントには[OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn&hl=ja)を使っています．

# NASにDLNAサーバを立てる
Dockerでできそうなことだし，Dockerを使います．

## minidlna
今回，DLNAサーバはminidlnaを使って立てることにします．実はminidlnaは使ったことがあるので知見を活かせそうということと，軽量であることが売りなので，NASの性能を落とさないという意味では迷わず採用できました．
※実は，NASに「メディアサーバ」なるアプリケーションがあって，これを使おうか考えたのですが…ライブラリの情報をクライアントにちゃんと送ってくれず，ライブラリ更新エラーが頻発し，断念しました．

使ったDockerイメージを載せておきます．
https://registry.hub.docker.com/r/magnaz/minidlna/

### 構築手順
構築手順は使ったイメージ以外[VPN専用DAAPサーバコンテナを作成する](https://qiita.com/Miutaku/items/ce1efbcca2570baf4bfb#vpn%E5%B0%82%E7%94%A8daap%E3%82%B5%E3%83%BC%E3%83%90%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)で書いたこととほぼ同じなので省きます．
違うこととすれば，音源ディレクトリのマウント先が違うことくらいです．DLNAコンテナ設定時，NASの音源ディレクトリをDocker内ディレクトリの`/opt/`にマウントします．ちなみに，miniDLNAは音源ディレクトリに対する書き込み権限がなくてもいいので読み込み専用(ro)でマウントさせました．一応ね．


# 忘れちゃいけない帯域の問題
配信側のサーバがこれでちゃんと立ち上がってくれたわけですが，__クライアント側の回線__がよろしくないと意味がないですよね．ストリーミングできません．
まあ，タイトルにも書いたハイレゾストリーミングですが…かなり帯域が大事になってきます．__常時5Mbps__以上は最低でも出せないとキツいです．また，1曲100~200MBの曲を1アルバムで聴いちゃうと__1GB~2GB__になりますね…
つまり，大量の通信が行われてしまうわけです．
ここで，考えられる対処方法としては2つあります．

- NASで音源をトランスコードして圧縮する．
- モバイル回線をパケット通信が使い放題で帯域がある程度確保されている契約に変えてみる．

前者は音質が悪くなってモチベが下がるので嫌ですね．
後者は安定していて使い放題な回線を利用しないといけません．

幸い，私が現在利用しているモバイル回線が楽天モバイルのRakuten UNLIMITで，23区内に住んでいるので，パートナーエリアにはあまり切り替わりません．
そこで，Rakuten UNLIMITでのVPN環境下でハイレゾ音源をストリーミングしたときの可用性を検証することにしたいです．

## 速度検証
(DLNAは，音源をストリーミングする際に最大12Mbpsまで達することがありました．その上での検証です．)

まず，VPN接続していないときの速度です．下り55.8Mbps出ているので大丈夫そうですね！
https://www.speedtest.net/my-result/a/6196671352

続いて，VPN接続時の速度です．下り20Mbps出てるし問題なさそうですね！
https://www.speedtest.net/my-result/a/6199364892

試しにストリーミングしてみました！24bit/96kHzのハイレゾ音源です．ffmpegでflacをWAVにしてから再生しているのでトランスコードしているだろと言われたらアレですが…可逆圧縮をWAVに戻しているだけですのでほとんど負荷はないです．リソースモニタを見てもあまりリソースを食ってるようには見えないです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/aefcf0ea-d84c-4938-07c3-40c7918c2857.png)

ただしこのストリーミング状態だと他の通信が帯域が足りずに不安定になるので，必要なアプリのみVPN接続するようにしました．今回使うVPN接続のプロファイルの設定を編集します．
「プロファイル」→<使いたい設定>のペンのボタン→「許可されたアプリ」タブ→「VPNは選択したアプリ以外のすべてのアプリから使用されます」と「アプリがVPNをバイパスできるようにする」の2つのチェックを外す→アプリのリストがあるのでBubbleUPnPにチェックを入れる．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/caa9c020-7463-13e5-d625-45df80b4e6e3.png)

この状態であれば，DLNAのようなVPNを使いたいアプリのみVPN側の帯域を消費するので，VPNトンネルの帯域が圧迫されなくなり，安定してストリーミングしながらWebブラウジングなどできるようになりました．

## 安定性の検証
一応，ちゃんと移動しながら使えるのか検証してみました．
検証環境は，私の家からマクドナルドまでの移動とします．
ちなみに，場所としては歩いて30分位かかるところなのですが，いい感じに住宅街を歩いていかないといけないため，電波が途切れて再生が止まるんじゃないかと思っていました．
しかし，杞憂だったようで，__全く音楽が途切れることなくマクドナルドに行くことができました．非常に安定しています．ハイレゾ音源を大量にストリーミングしても問題ありません！__

ただし，一個問題がありまして，楽天モバイルは自社回線だと10GB/1日の通信で帯域制限がかかってしまうようです．(2020-06-20現在)

そこで，制限後もストリーミングできるか検証しました．
ストリーミングしていない状態での制限後の速度は次のとおりです．概ね3Mbpsに制限しているようですね．
https://www.speedtest.net/my-result/a/6196366545
この状態でストリーミングしてみたら流石に定期的に曲が止まりました．しかし，ハイレゾ音源だから止まったのであって，CDのFLACやWAV音源ならストリーミングできました．

でもそもそも，10GB/1日なんて，私なら200MBのハイレゾ音源50曲聴いてようやっとなので，3分×50曲だとして150分もハイレゾ音源を聴き続けないと達しません．一番長くても通勤の数十分の間だけストリーミングできたら良いので十分です．

# 最後に
非常に可用性が高いハイレゾストリーミング環境ができました．
定額ハイレゾストリーミングサービスにmora qualitasとかもあるのですが，聴きたい曲がない割に料金がそれなりにするので，やっぱり音源は自分で持っておくのがベストだなと思いました．
一個欠点を上げるなら__非常にバッテリを消費する__ことですかね…平気で20%/1hくらいのペースで減っていくので，通勤時間が長い人はモバイルバッテリを使うとかしないといけないと思います．

## 追記
実は，VPN接続時，BubbleUPnPを開いたあとはしばらくminidlnaサーバを見つけてくれなかったんです．これの原因は，miniDLNAがローカルに自身の存在を通知する間隔(Broadcastする間隔)が800秒くらいになっていたからです．いろんな記事で`notify=interval`はメディア更新頻度の値だと言っていますが，そもそも名前からしてブロードキャスト間隔の調整をする設定じゃないんすかね．
まあそれはいいとして，`minidlna.conf`を開き，

```bash:/etc/minidlna.conf
#notify interval in seconds. default is 895 seconds.                                                                                           
notify_interval=15 
```

としたら15秒おきにサーバがクライアントに教えてくれます！
これでアプリを開いてしばらく待たないとクライアントが出ないってことがなくなりました！
当然，通知が頻繁に飛んでくる分通信量は増えるんですが，1日中VPN接続していても数GBとかになるわけではないでしょうし問題なしです．非常に快適になりました！