ド素人がicecast2とliquidsoapでストリーミングに挑戦

ラジオのパーソナリティ
©いらすとや.

icecast2のインストール・設定・起動

ストリーミングサーバとしては今回はicecast2を使う。これでなくても良いだろうけど。

$ sudo apt install icecast2
公開用のホスト名(初期値localhost)と管理用パスワードなど3つほどの入力を求められる。

icecast2設定を行う。

/etc/icecast2/icecast.xml (編集)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<icecast>
    <location>Japan</location>
    <admin>streamer@example.com</admin>

    <limits>
        <clients>100</clients>
        <sources>10</sources>
        <queue-size>524288</queue-size>
        <client-timeout>30</client-timeout>
        <header-timeout>15</header-timeout>
        <source-timeout>10</source-timeout>
        <burst-on-connect>0</burst-on-connect>
        <burst-size>0</burst-size>
    </limits>

    <authentication>
        <source-password>秘密</source-password>
        <relay-password>秘密</relay-password>
        <admin-user>admin</admin-user><!-- 変えた方が良いかも -->
        <admin-password>秘密</admin-password>
    </authentication>

    <hostname>stream.example.com</hostname>


    <!-- for liquidsoap (wo/TLS)-->
    <listen-socket>
        <port>8000</port>
    </listen-socket>

    <!-- Main Stream (w/TLS)-->
    <listen-socket>
        <port>8443</port>
        <ssl>1</ssl>
    </listen-socket>

    <http-headers>
        <header name="Access-Control-Allow-Origin" value="*" />
    </http-headers>

    <fileserve>1</fileserve>

    <paths>
        <basedir>/usr/share/icecast2</basedir>

        <logdir>/var/log/icecast2</logdir>

        <webroot>/usr/share/icecast2/web</webroot>
        <adminroot>/usr/share/icecast2/admin</adminroot>
        <alias source="/" destination="/status.xsl"/>
        <ssl-certificate>/etc/icecast2/ssl/merge.pem</ssl-certificate><!-- TLS証明書 -->
    </paths>
    
    <logging>
        <accesslog>access.log</accesslog>
        <errorlog>error.log</errorlog>
        <loglevel>3</loglevel> <!-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
        <logsize>10000</logsize> <!-- Max size of a logfile -->
    </logging>

    <security>
        <chroot>0</chroot>
    </security>
</icecast>

先ほど入力した3つのパスワードはこのファイルに書き込まれている。 <limits></limits>の中。インストール直後の質問をスキップした場合は手動で入力。(なんと平文)
ウェブ管理用等のアカウント名は初期値は admin のようだが、おそらくこれも変更した方が良さげ。

TLSの証明書は公開鍵と秘密鍵を1つのファイルにマージしなければならないみたい。公開鍵(上)+秘密鍵(下)みたいな。

サンプル設定ファイルでは配信用のポートの初期値は8000だが、そのポートをlocalhost, LAN, DMZ内のliquidsoap用にして、8443 (TLS)を視聴者向けのストリーミングポートにする。なので、ファイヤウォールは外部からの8443は開けて、8000は外には開かない。

初歩的な部分で忘れがちだが、ログ置き場を適切なユーザーで作っておかないとicecast2が起動してくれない。ログ用ディレクトリをたとえば666で誰でも読み書きできるパーミッションを付けても動かないときは動かない?ユーザーicecast2、グループicecastで作った方が確実かも。ちなみにicecast2の起動スクリプトは/etc/init.d/icecast2だった。これは気に入らないので普通のsystemd用に作り直した方が良いかも。

$ sudo systemctl enable icecast2   #サービス有効化
$ sudo systemctl start icecast2    #サービス開始

icecast2はDebian/Ubuntuのパッケージにsystemdのサービス起動用ファイルが入っているので、ただ有効化・起動を実行するだけで簡単。

ブラウザでhttp://live.example.com:8000 または http://live.example.com:8000/status.xsl を開くとicecast2のステータス画面が表示される。 この設定ではicecastではストリーミングの中身が何も無い状態。次のliquidsoapで。

Liquidsoapのインストール

Debian/Ubuntuのパッケージだとliquidsoapのバージョンが古い。
しかし、2020年12月上旬現在はopamなどでビルドしようとするとliquidsoapのビルドで必要とするシェアドライブラリのバージョンが古いため苦労するかも。 libshineとかlibmad0あたりは特に。この辺り柔軟に根気強く対応できる人以外にはビルドはオススメしない。
バージョンが少し古くてもDebian/Ubuntuのパッケージでインストールする方が圧倒的に簡単。

$ sudo apt install liquidsoap
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:

中略

提案パッケージ:
  libaudio2 libsndio6.1 libbluray-bdj libcamomile-ocaml-dev libfftw3-bin libfftw3-dev libgd-tools
  libvisual-0.4-plugins jackd2 liblo-dev opus-tools pulseaudio libraw1394-doc librsvg2-bin serdi sndiod sordi
  libsox-fmt-all festival mplayer youtube-dl opencl-icd
推奨パッケージ:
  libaacs0 libgdk-pixbuf2.0-bin gstreamer1.0-plugins-base librsvg2-common va-driver-all | va-driver vdpau-driver-all
  | vdpau-driver vorbis-tools vorbisgain
以下のパッケージが新たにインストールされます:
  fontconfig libao-common libao4 libaom0 libass9 libasyncns0 libavc1394-0 libavcodec58 libavdevice58 libavfilter7
  libavformat58 libavutil56 libbluray2 libbs2b0 libcairo-gobject2 libcamomile-ocaml-data libcdio-cdda2
  libcdio-paranoia2 libcdio18 libchromaprint1 libcodec2-0.9 libdatrie1 libdc1394-22 libdrm-amdgpu1 libdrm-common
  libdrm-nouveau2 libdrm-radeon1 libdrm2 libexif12 libfaad2 libfftw3-double3 libflac8 libflite1 libfribidi0 libgavl1
  libgd3 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgif7 libgl1 libgl1-mesa-dri libglapi-mesa libglvnd0
  libglx-mesa0 libglx0 libgme0 libgraphite2-3 libgsm1 libgstreamer-plugins-base1.0-0 libharfbuzz0b libiec61883-0
  libjack-jackd2-0 libjbig0 libjpeg-turbo8 libjpeg8 liblilv-0-0 libllvm10 liblo7 libmad0 libmp3lame0 libmpg123-0
  libmysofa1 libnorm1 libnuma1 libopenal-data libopenal1 libopencore-amrnb0 libopencore-amrwb0 libopenjp2-7
  libopenmpt0 libopus0 liborc-0.4-0 libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpgm-5.2-0 libportaudio2
  libpostproc55 libpulse0 libraw1394-11 librsvg2-2 librubberband2 libsdl-image1.2 libsdl-ttf2.0-0 libsdl1.2debian
  libsdl2-2.0-0 libserd-0-0 libshine3 libsnappy1v5 libsndfile1 libsndio7.0 libsodium23 libsord-0-0 libsoundtouch1
  libsox-fmt-alsa libsox-fmt-base libsox3 libsoxr0 libsratom-0-0 libssh-gcrypt-4 libswresample3 libswscale5
  libtag1v5 libtag1v5-vanilla libthai-data libthai0 libtiff5 libtwolame0 libva-drm2 libva-x11-2 libva2 libvdpau1
  libvidstab1.1 libvorbisenc2 libvpx6 libwavpack1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwebp6
  libwebpmux3 libx11-xcb1 libx264-155 libx265-179 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0
  libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcursor1 libxdamage1 libxfixes3 libxi6 libxinerama1 libxkbcommon0
  libxpm4 libxrandr2 libxshmfence1 libxss1 libxv1 libxvidcore4 libxxf86vm1 libzmq5 libzvbi-common libzvbi0
  liquidsoap ocaml-base-nox ocl-icd-libopencl1 shared-mime-info sox x11-common
アップグレード: 0 個、新規インストール: 153 個、削除: 0 個、保留: 89 個。
71.3 MB のアーカイブを取得する必要があります。
この操作後に追加で 813 MB のディスク容量が消費されます。
続行しますか? [Y/n]

Liquidsoapをバッチ処理の簡易マネージャの類かな?くらいにあなどっていたこともあって、まさかの大量のパッケージを必要とすること愕然。まぁ要るんだと言われたら仕方ないのでこのまま[Y]でインストール。

結構重要なのにDebian/Ubuntuのパッケージのインストールでやってくれないことがある。
下の3行を実行しておかないと、liquidsoapで何かの機能を使おうとしたときに「ライブラリpervasives.liqとそれに付随するスクリプトがインストールされている必要があります。」という条件から外れるので盛大にトラブる。
liquidsoapは設定ファイルで特にインクルードしなくても /usr/local/lib/liquidsoap/<version> の pervasives.liq ファイル他を読んでそこに定義されている関数等が使えるのだけど、 Debian/Ubuntu のパッケージではなぜか /usr/share/liquidsoap/libs にインストールしちゃうのでliquidsoapが読めない状態になっている。そこで下の3行。
なお、バージョン(下の例だと1.4.1)は必要に応じて変更。

$ sudo mkdir /usr/share/liquidsoap/1.4.1
$ sudo ln -s /usr/share/liquidsoap/libs /usr/share/liquidsoap/1.4.1/libs
$ sudo ln -s /usr/share/liquidsoap/bin /usr/share/liquidsoap/1.4.1/bin

Debian/Ubuntuのliquidsoapパッケージはsystemd用のサービス起動関係が用意されていない。そこで最低限動くだけの簡易的なのを作った。

/lib/systemd/system/liquidsoap.service (新規)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=Liquidsoap daemon
Documentation=http://liquidsoap.fm/
After=network.target

[Service]
Type=simple
User=root
Group=liquidsoap
PIDFile=/etc/liquidsoap/liquidsoap.pid
ExecStart=/usr/bin/liquidsoap /etc/liquidsoap/main.liq
ExecStop=/usr/bin/killall liquidsoap

[Install]
WantedBy=multi-user.target

pidファイルは/run以下に置いたらパーミッションでエラーになってliquidsoapが落ちた。/run/liquidsoapディレクトリを作ってそのディレクトリを書き込み可にしたらliquidsoapはそのときは落ちなかったけど、システムを再起動したら /run/liquidsoap ディレクトリが消えて再びliquidsoapが落ちた。liquidsoap起動直前に/run/liquidsoapディレクトリを作るようにExecStartPre行を書けば良いのだが、そもそも/runディレクトリに拘る必要もないので/etc/liquidsoapに発生するようにした。作法的にはどうかとは思う。
liquidsoap起動に必要なメインの設定ファイルは /etc/liquidsoap/main.liq ということにした。

liquidsoapの設定

/etc/liquidsoap/main.liq (新規)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
set("init.daemon.pidfile.path", "/etc/liquidsoap/liquidsoap.pid")
set("init.daemon",true)
set("log.file.path","/var/log/liquidsoap/radioliq.log")
#set("log.level",4)


failover = single("/media/streaming/fail.mp3")
music = playlist("/etc/liquidsoap/music.pls")
news = single("/media/streaming/news.mp3")

jingle1 = single("/media/streaming/jingle1.mp3")
jingle2 = single("/media/streaming/jingle2.mp3")
jingle3 = single("/media/streaming/jingle3.mp3")

#def news98()
#    request.create("/media/streaming/news98.mp3")
#end

#news99 = request.queue(
#   queue = [
#       request.create("/media/streaming/jingle2.mp3"),
#       request.create("/media/streaming/news_open.mp3"),
#       request.create("/media/streaming/news99.mp3"),
#       request.create("/media/streaming/news_close.mp3")
#   ]
#)

stream = fallback(
    [
        #request.queue(id="request"),
        switch(
            track_sensitive=false,
            [
                ({0h0m-0h2m},   once(jingle1)),
                ({1h0m-1h2m},   once(jingle2)),
                ({2h0m-2h2m},   once(jingle3)),
                ({3h0m-3h2m},   once(jingle1)),
                ({4h0m-4h2m},   once(jingle2)),
                ({5h0m-5h2m},   once(jingle3)),
                ({6h0m-7h},     once(news)),
                ({7h0m-7h2m},   once(jingle2)),
                ({8h0m-8h2m},   once(jingle3)),
                ({9h0m-10h},    once(news)),
                ({10h0m-10h2m}, once(jingle2)),
                ({11h0m-11h2m}, once(jingle3)),
                ({12h0m-13h},   once(news)),
                ({13h0m-13h2m}, once(jingle2)),
                ({14h0m-14h2m}, once(jingle3)),
                ({15h0m-16h},   once(news)),
                ({16h0m-16h2m}, once(jingle2)),
                ({17h0m-17h2m}, once(jingle3)),
                ({18h0m-19h},   once(news)),
                ({19h0m-19h2m}, once(jingle2)),
                ({20h0m-20h2m}, once(jingle3)),
                ({21h0m-22h},   once(news)),
                ({22h0m-22h2m}, once(jingle2)),
                ({23h0m-23h2m}, once(jingle3)),
               #({23h0m-23h30m}, request.dynamic(news98)),
               #({23h0m-23h30m}, news99)),
                ({ true }, music),
            ]
        ),
    failover
    ]
)

output.icecast(
    %vorbis.cbr(
        samplerate=44100,
        channels=2,
        bitrate=128
    ),
    host = "localhost",
    port = 8000,
    password = "秘密",
    mount = "/stream", name="秘密のストリーミング",
    description = "ストリーミングの説明",
    stream
)

liquidsoapを全く理解していない素人が作った設定です。liquidsoapのドキュメントは、バカ避けになっていて「がとらぼ」の中の人の悪いアタマでは全く理解できない代物なので、もっとも簡単な関数だけを使った試行錯誤の結果がコレ。エキスパートならこんなアホなのじゃなく良いのを作ってくれる筈。

あと、この例では音量正規化の normalize() やクロスフェードの crossfade() やモノラルをステレオ化する audio_to_stereo() のような良く使うだろう関数も敢えて使ってない。効果を与えたい対象を関数に放り込んでやるだけ。

指定されている楽曲ファイルが存在しないなど、最も正常に再生できない条件のときにはfailover(名前は任意)で指定したfail.mp3ファイルが再生される。
そうでなければ通常はmusic(名前は任意)で指定した/etc/liquidsoap/music.pls (プレイリスト)が再生される。
さらに、switchで簡単なスケジュールを作っている。このスケジュールは、楽曲等を再生するだけでライブ放送の割り込み等は無し。
上の例では、6, 9, 12, 15, 18, 21時にニュースが再生される。ニュース再生のある時間を除く毎時0分にはジングル(3種の1つ)が再生される。

ジングルといえば普通は1分以内だろうと思われるが、本当に1分以内であれば、開始時間だけを書けば良いみたい。(例13h00mとか13h0sとか)
しかし、ジングルであろうと他であろうと1分を超えるなら開始時刻だけでなく終了時間も書く。 (例: 13h00m-13h30m)でないと、開始時刻だけの場合は再生開始から1分でその再生が打ち切られてしまう。このとき、終了時間については、ジングルの再生時間ぴったりがおそらくは良いのだろうけど、ぴったり以上で且つスケジュールの次の再生が始まるまでの時間であれば問題無いよう。例えば、13h0m-13h30mのように長い時間(この例では30分)を指定して1,2分の短い音声を再生してもonce()を使えば1回再生した後にswitchのデフォルト(上の例だとmusic)が再生されるので問題がないことになる。なお、once()を使わないと、指定した時間内を使って指定した1つの音声ファイルやプレイリストのループ再生になる。例えば13h0m-13h30mの30分間ずっとジングルが繰り返されるようなことになる。

簡単に考えている素人には挙動の想像がつかないのが、再生途中に再生が打ち切られた場合に、次に呼ばれたときにその続きが再生されるというところ。ヘタに打ち切りを発生させると後で影響してくるのでとても怖い。キューを停める・スキップする・リセットするというのは「がとらぼ」の中の人はまだ理解していない。キューの操作が理解できれば、もしかしたら怖くはないのかもしれないけど。

single(音声ファイル), playlist(プレイリストファイル)の単独利用だとループ再生、once(single(音声ファイル)), once(playlist(プレイリストファイル))なら音声ファイル或いはプレイリストを1回再生して停まる
そういうことであるのなら、hoge = once(single(foo)) という風にonce()指定でhogeを作っておいて、switchの中でhogeを呼ぶだけで良いのではないかと普通は考えそうな気もするが、それが罠で、この場合はhogeが1度だけ実行されるものの、別の時間にhogeを呼んでも再生してくれない。hoge = single(foo)でonce()無しのhogeを作って、switchの中でonce(hoge)であれば、別の時刻にonce(hoge)を呼んでもそれが再生される。

liquidsoapのこのような挙動はとにかくクセが強く、ドキュメントを読んだ程度では理解できず、全く思い通りに動いてくれない。1ヶ月触った程度では本当に全然ワケワカラン。
liquidsoapのことをググると簡単に番組が組めるようなことが書いてあったりするが、そんなこと書くのはロクにliquidsoapを触ってない人じゃないかしら?楽曲再生で一番最初に触れるであろうsingle(), playlist()関数1つ使うにも挙動に凄いクセがあるような代物を簡単に使いこなせるワケがない。liquidsoapで番組(スケジュール)を組んで不特定多数に聴いて貰おうなんていうことになると、liquidsoapによほど精通した人が綿密に設定を組まないとしょっちゅう放送が停まったり予定外の内容が流れたとかエライことになりそうに思う。

liquidsoapのクセのある挙動
上で書いたことを図にしてみた。

最後の方のoutput.icecast()が出力先のicecastなので、host, port, passwordの値を先に設定したicecastに合うようにする。icecast2とliquidsoapを同じホストで動かすならホスト名は localhost にする。

$ sudo systemctl enable liquidsoap   #サービス有効化
$ sudo systemctl start liquidsoap    #サービス開始
なお、systemdのサービス実行ではなく、単に手動でliquidsoapを起動するなら
$ liquidsoap /etc/liquidsoap/main.liq  (main.liqの中でdaemon稼働を指定したらこれでliquidsoapがバックグラウンドで動く)

icecastの設定(icecast.xml)でstream.example.com:8443 (TSL)でストリーミングを行う設定にした。また、liquidsoapの設定(main.liq)の59行目でマウントポイントを/streamにした。
なので、ストリーミングURLは https://stream.example.com:8443/stream になる。このURLをウェブブラウザで開くとかネットラジオのプレーヤーに登録するとストリーミングを視聴できる。(今回の設定では聴くだけだが)

ルーターが非力でかつNICが糞だとストリーミングを続けるとときどきルーター(のNIC)が落ちるのでストリーミング用のサーバよりルーターのNICに金かけた方が良いっぽい。転送量が多いとか負荷が高いとかいうわけではないと思うけどNICが落ちるのは何でかしら。

liquidsoapの設定が自由自在なエキスパートを除いてはliquidsoapを直に触って番組を組んだりするのはやめた方が無難で、 AirTime, AzuraCast, LibreTime, MSCP Pro - Media Server Control Panel(有料), OpenBroadcaster(気色が違うが), あたりのGUIのツールを利用する方が良さそう。

初稿ではonce(single())の挙動を理解できていなかったのでrequest.dynamic()でジングルを実現していたが、ようやくonce()を使う場合の挙動の謎が解り始めたのでonce(single(hoge))を使うように大幅に変更して、図も追加した。
なお、liquidsoapについてはやっぱり殆ど理解できていない。本当に難しい。

中華の安物ラギッドフォン風スマホケースを買ってみた

基本的にスマートフォンについては裸族だったのでケースを付けずに持ち歩いていたのだが、今年購入したXiaomiのRedmi Note 9sは背面のカメラ部が飛び出ているのでケース無しで使ってるとカメラ部分のガラス?が割れたり欠けたりしそうで怖いと思ったのでケースを付けることにした。そもそも標準でTPUケースが付属するし。(そのケースがちょっと気に入らない)
で、8月にAliExpressで92円送料無料で購入した激安ケースが失敗だったのでリベンジで新しく買い直したのだが、10月に注文して12月に入ってようやく届いた。(購入時355円送料無料)

中華スマホケース
上は、このページに書いている製品ではありません。もしも、これから購入するならコレかなと思った品。(ちょっと高いけど)
購入した商品の紹介リンクが作れないようなので代わりに。

中華スマホケース 1
最近中華通販でよく見かけるほとんどプチプチが効いていないペラッペラの白色プチプチ封筒で届いた。ペラペラ封筒越しに中身のケースの内側の形状が判るようなの。

中華スマホケース 2
中に入ってたのがこれ。やっぱり封筒以外の養生は無かった。まぁ、丈夫さをウリにした商品なのでこれが「割れてた」だとケースとしては失格だよね。

中華スマホケース 3
大部分はプラスチック(硬い樹脂)で、上下の縁と四隅と表側(スマホの画面側)はゴムっぽい素材(TPU)になっている。
四隅の少し厳つい部分で衝撃を吸収するようなことが商品説明ページで謳われていたが、疑わしいかな?実際に角落ちさせてみたい気も少しはあるのだが、スマホが壊れたらシャレにならないのでこのブログの小心者は落下実験はしていない。
そして、予想はしてたけどやっぱり安っぽさがハンパない。

中華スマホケース 4
このケースを使うと厚さは約12mmになる。
USBポートとイヤホン端子部分はむき出しでフタはない。製品紹介ページにはフタがあるような画像が載ってたけど実物には無いの、このいいかげんさはさすが中華。Redmi Note 9S付属のTPUケースはUSBポートのフタが付いているのでポートにホコリが入らないのが良いが、そのフタが邪魔というのはあるのでどちらが良いかは好みかな?

中華スマホケース 5
カメラ部分はケースよりも低く凹になるので机の上などに乱暴に置いてもカメラ部分のガラス?が割れたり欠けたりすることはなさそう。

中華スマホケース 6
ケースにスマートフォンを入れるのは苦労しないが、意外とピッタリしっかりした造りで勝手にケースが脱げたりすることはなさそう。脱着についてはRedmi Note 9sに付属するTPUケースと同等。側面の指紋認証付きスイッチ部は本体むき出しだが、となりの音量ボタンはケース側に付いているボタンに覆われる。

中華スマホケース 7
こちらは8月に購入して失敗だと思ったケース。
Redmi Note 9sのバックパネルがガラスなのにケースのバックパネルもガラスという意味解らなさが面白いかなと思ったが、ダサすぎて1回も使わなかった。
この商品はバックパネルがガラスということで、発泡スチロールのしっかりした容器に入って送られてきた。中身92円送料無料とは思えない。良かったのはここまで。

中華スマホケース 8
発泡スチロールのフタを開けるとケースの内側とご対面。内側に模様があるのは前半のラギッドフォン風ケースも同じだった。
側面4面は超ペラペラなゴム風素材で、バックパネルは硬いプラスチック(樹脂)の上に写真付きガラスパネルが貼り付けてある。

中華スマホケース 9
バックパネルの見た目。「石」の断面風の写真が貼ってある。判りにくいとは思うが、実物は解像度の荒いカラープリンタで印刷した写真感が強く石っぽくない。ガラスの縁は丸め加工がしてあるので持った感じは悪くないのかもしれないが、背面がガラス板で縁ぎりぎりまでまっ平なので側面の高さ(厚み)が際立つ。Redmi Note 9s付属のTPUケースは背面の縁から1cmあたりから丸めなフォルムになっているので実際より薄く感じられる造り。
しかも、側面4面がゴム風な素材なので見た目の安っぽさが我慢できない。

中華スマホケース 10
下部のUSBポートとイヤホン端子とスピーカー、マイクの穴。穴の縁は丸め加工がされていてここは意外と悪くない。また、写真に写っていない右サイドの下部にはストラップ用の穴も設けられている。ストラップホールをありがたがる人はいると思うが、ペラペラゴム風素材にストラップホールがあってもすぐに千切れそうで怖くて使えないかな?

中華スマホケース 11
Redmi Note 9s付属のTPUケース。作りは悪くない。本体の形状に忠実なのでバックパネル側も隙間なく本体にぴったり。USBポートのフタ付き。

中華スマホケース 12
加工も凝っていて、拡大してみると密集したドット模様。
とても良い品だとは思うけど2点ほど気に入らない。
ちょっと黄色っぽいというか黄ばんだ感じ。これは使っていてそうなったということではなく、最初から少し黄色っぽく、購入から5ヶ月ほどの間に変化した感じはない。購入したスマホ本体の色がホワイトなのだが、この黄ばんだような色味はイヤ。
もう一つは本体形状に合わせてぴったりは良いのだけど、コンパクトに纏まったのがアダで、本体の重さがダイレクトに感じられる。Redmi Note 9sは本体重量が209gということで普通のスマートフォンとしては少し重い部類。それがコンパクトだとズシっと感じてしまう。今回購入したラギッドフォン風ケースは実際にはほんの僅かに大きいだけだけど、縁の部分が大きいのが良く効いて大きさの割には軽く感じられる、実際には重いんだけど錯覚で少し軽くなった、そんな感じ。

今回購入したラギッドフォン風ケースは、見た目が安っぽいのが気に入らないが、意外と持ち心地が良いのと(錯覚で)電話機が軽く感じられるのが気に入った。暫く使ってみようと思う。

ラギッドフォン風ケースはベゼルが5mmほどあるので、気付かずに手の一部が画面の縁に触れて誤反応というのが激減。ベゼルが薄いと見た目は良いけど片手で使い勝手が悪いのよね。

Up