HDMI-CEC

提供: ArchWiki
2024年4月5日 (金) 22:02時点におけるKusanaginoturugi (トーク | 投稿記録)による版 (→‎ソフトウェアセットアップ: 翻訳)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

High-Definition Multimedia Interface - Consumer Electronics Control は、HDMI 接続内の追加の低速(50 B/s)バスであり、HDMI デバイスの「ネットワーク」が互いに通信するために使用できます。これにより、HDMI デバイスはお互いにオンまたはオフにすることを通知したり、テレビが入力を切り替えたり、リモコンのボタンが押されたりするなどの操作が可能になります。PC セットアップでは、通常、HTPC(ホームシアターPC)セットアップで遭遇します。

様々な理由から、ほとんどの PC GPU は CEC のハードウェアサポートを持っていません。ビデオゲームコンソールやセットトップボックスは通常、CEC ピンを駆動するために外部チップセットを含める必要があります。Raspberry Pi で見られる VideoCore GPU のようにネイティブ CEC サポートを持つデバイスもありますが、ほとんどのハードウェア構成では追加のハードウェアが必要です。

機能

CEC (Consumer Electronics Control) の主な目的は、テレビがそれに接続されているデバイスの状態を把握し、制御することを可能にすることです。そのため、特定の使用例に対応する「機能」のいくつかに分けられており、デバイスは発信者/フォロワーとしての役割、能力、ユーザー設定に基づいて、これらの機能をサポートするかどうかを選択できます。

標準化された機能は以下の通りです:

ワンタッチプレイ
デバイスが直ちにアクティブソースになることを希望していることを示し、自動的にテレビをオンにすることができます
ルーティング制御
テレビがHDMIスイッチを制御できるようにし、デバイスが現在アクティブなソースを確認できるようにします
リモートコントロールパススルー
デバイスが互いにリモコン信号を送信できるようにします。通常はテレビからアクティブソースへ送信されます
デッキコントロール
映画/音楽プレイヤーを制御し、その再生状態を照会する
スタンバイ/システムスタンバイ
デバイスが別の特定のデバイスの電源を切ることを要求したり、システム上のすべてのデバイスが今電源を切るべきだと放送することができます
電源状態
デバイスがスタンバイモードにあるか、オンになっているか、またはオンになるプロセス中にあるかを調べることができます
システムオーディオコントロール
テレビのオーディオリターンチャネルを介して接続されたAVレシーバーを制御できるようにし、音量を変更したりレシーバーの電源を入れたり切ったりできます
チューナーコントロール
任意のデバイスがチューナーデバイスに知られているテレビチャンネルのリストを通過し、アクティブなチャンネルの情報(アナログテレビのチャンネル番号やデジタルテレビのDVB/ATSC/ARIBトランスポートストリーム情報など)を照会できます
ワンタッチレコード
レコーダーがテレビが現在表示しているチャンネルを照会できるようにし、そのレコーダーが同じチャンネルにチューニングして録画を開始するか、既に現在アクティブなHDMIソースであれば自身や下流デバイスを録画すべきかを知ることができます
タイマープログラミング
テレビが特定の時間に特定のソースの録画を開始するためにレコーダー上のタイマーを設定できるようにします
OSD表示
デバイスがテレビ上にメッセージを表示できるようにします。1から13文字のASCII文字で
ダイナミックオートリップシンク
テレビがオーディオシンクへのプレゼンテーション遅延の変更を放送できるようにします。これは、独自のスピーカーを持つソース(PCなど)が画像との遅延補償に使用できます。
ヒント: リストにないもの:デバイスメニューコントロール(CEC 2.0で廃止)、OSD名転送(cec-ctlによって処理)、システム情報、ベンダー固有のコマンド(標準化されたメッセージなし)、オーディオレートコントロール(TV-AVのみ)、オーディオリターンチャネルコントロール(TV-AVのみ)

PC のようなデバイスにとって、これらの中で最も有用なのは「リモートコントロールパススルー」でしょう。HTPC にとっては「システムスタンバイ」が有用かもしれませんが、スクリーンがオフになったときに通常スリープ状態に入ることが期待されないより一般的な用途のマシンでは疑問の余地があります。「ルーティングコントロール」は、テレビがその入力を表示しようとするときにシステムを起動させるために使用できますが、接続されたPCがサスペンド中にCECトラフィックをリッスンする方法を持っている場合に限ります。「システムオーディオコントロール」は、一部の HDMI サウンド出力にとって便利ですが、現在、PipeWirePulseAudio といったもので音量制御の手段としては機能していません。

ハードウェアセットアップ

Linux のカーネルには既に CEC イベントに自動的に応答し、処理するための組み込みのサブシステムがありますが、ハードウェアが正しく機能するためには最初に設定が必要になる場合があります。

Native CEC

Native CEC は主に ARM デバイスで見られます。x86 世界では、DisplayPort経由のトンネリングが最も簡単なオプションです。それ以外では、一部の Chrome OS デバイスと SECO UDOO のシングルボードコンピューターのみが CEC を提供しています。

DisplayPort 経由のトンネリング

これは i915nouveauamdgpu ドライバーで機能します。2014 年に導入された DisplayPort 1.3 標準では、DisplayPort から HDMI アダプターを使用して補助チャネルを介して CEC 信号を双方向に転送することができます。これはアダプターが通常サポートしていない種類の機能であり、一般的ではありませんが、USB-CEC アダプターよりも直感に反して CEC のトンネリングを DisplayPort 経由で使用する方が安価で簡単な場合があります。CEC サブモジュールのカーネルドキュメントページには、動作が確認されたアダプターのリストがあります。

CEC アダプター

ノート: Kodi で HDMI-CEC を使用しようとしている場合、それは Pulse-Eight および Raspberry Pi の CEC 制御モードの両方の組み込みサポートを持っており、以下の設定と互換性がありません。

PulseEight USB アダプター

PulseEight USB-CEC アダプターは、「PC 側」コネクタから「TV 側」コネクタへ HDMI コネクタのすべてのピンを受動的に延長しますが、CEC ピンを除きます。そのピンを通るデータは、PC が CEC トラフィックを制御し監視できるように USB シリアルインターフェース上で公開されます。シリアルデバイスは、カーネルがそれを CEC アダプターとして認識し、引き継ぐ前に手動でそのラインディスプリン(TTY が特定の既知のタイプであり、動作にドライバーが必要であることをカーネルに信号を送るフラグ)を設定する必要があります。シリアルデバイス API の制限のためにこれを自動的に行うことはできないため、現在はデバイスが接続されたときにinputattach --pulse8-cec ...を実行する udev ルールsystemd ユニット(udev ルールでは長時間実行またはフォークするプロセスを起動できないため)を組み合わせて実現するのが最善の方法です。

このシリアルインターフェイスはデバイスノード /dev/ttyACMX として現れ、カーネルドライバーが引き継いで後で必要になる /dev/cecX デバイスを作成するために、ラインディスプリンを設定して inputattach ユーティリティが必要です。これには linuxconsole パッケージが必要です。

ノート: 以下のルールで @$devnode を変更しないでください。これは udev の文字列置換です。
/etc/udev/rules.d/pulse8-cec-autoattach.rules
SUBSYSTEM=="tty" ACTION=="add" ATTRS{manufacturer}=="Pulse-Eight" ATTRS{product}=="CEC Adapter" TAG+="systemd" ENV{SYSTEMD_WANTS}="pulse8-cec-attach@$devnode.service"
/etc/systemd/system/pulse8-cec-attach@.service
[Unit]
# Should be called as "pulse8-cec-attach@-dev-ttyACM0.service" or similar
Description=Configure USB Pulse-Eight serial device at %I
ConditionPathExists=%I

[Service]
Type=forking
# inputattach is built without systemd daemon support by default, so systemd will have to guess the PID.
# https://sourceforge.net/p/linuxconsole/code/ci/a3366c0d5f82485e6aae7b005ec7a2d9a93bf458/tree/utils/inputattach.c#l1233

ExecStart=/usr/bin/inputattach --daemon --pulse8-cec %I

しかし、USB デバイス接続は、システムがスリープから復帰するときに通常リセットされます(これは「reset-resume」として知られています)。これは、コンピュータがサスペンドされた場合、シリアル接続が失われることを意味します。さらに、通常、シリアル接続は復帰時に切断されがちです。このため、上記のルールを何らかの方法で再度トリガーする必要があります。

残念ながら、上記のルールが反応する ttyACM* オブジェクトを担当するcdc_acmドライバは、接続がリセットされてラインディスプリンが失われたことについての uevent を発生させず、USB デバイス直接にルールをフックすることはできません。代わりに、正しいタイミングで上記の使用されたルールを再度トリガーする最も確実な方法は、リセット時に USB デバイスを再設定することを強制して ttyACM* オブジェクトを削除して再作成することです。これにより、udev は USB デバイスがリセットされて列挙されるときを追跡でき、DEVNUM プロパティがゼロになり後で復元されること、bConfigurationValue sysfs 属性を触ることにより、接続が再開されることを確実にします。

/etc/udev/rules.d/pulse8-cec-autoattach.rules
SUBSYSTEM=="tty" ACTION=="add" ATTRS{manufacturer}=="Pulse-Eight" ATTRS{product}=="CEC Adapter" TAG+="systemd" ENV{SYSTEMD_WANTS}="pulse8-cec-attach@$devnode.service"

# Force device to be reconfigured when reset after suspend, otherwise the ttyACM link is lost but udev will not notice.
# A usb_dev_uevent with DEVNUM=000 is a sign that the device is being reset before enumeration.
# Re-configuring causes ttyACM to be removed and re-added instead.
SUBSYSTEM=="usb" ACTION=="change" ATTR{manufacturer}=="Pulse-Eight" ATTR{product}=="CEC Adapter" ENV{DEVNUM}=="000" ATTR{bConfigurationValue}=="1" ATTR{bConfigurationValue}="1"

これは基本的に、USB アダプタがスリープから出た直後に抜き差しされたかのように機能し、以前の SUBSYSTEM=="tty" ACTION=="add" ルールが再び実行されることを保証します。これにより、デバイスが使用可能な状態に戻るとすぐに systemd サービスが再起動されることが保証されます。

ソフトウェアセットアップ

CECサブシステム設定

CECサブシステムの設定が完了し、/dev/cec0 が作成されたので、他の CEC デバイスが PC について知るように PC を設定することが可能になりました。コマンドラインを使用している場合、CEC デバイスは通常 v4l-utils の一部である cec-ctl を介して制御されます。

一つ注意すべき点は、CEC ピンだけでは、有効な CEC メッセージを送信するために必要な情報が十分ではないということです。ピン13(CEC)のみを監視する CEC アダプターは、「物理アドレス」(HDMI デバイスの「ツリー」内のポート番号による位置、例えば 3.1.0.0 など)を知ることができず、論理アドレス割り当て手続きを完了するためにこれを把握する必要があります。論理アドレスがなければ、デバイスはブロードキャストメッセージのみを受信および送信できます。物理アドレスはピン 16(DDC/EDID)を介して伝えられるため、CEC サブシステムの設定には、物理アドレスをディスプレイの EDID から抽出できるように、どのディスプレイ出力ポートがその CEC オブジェクトに関連付けられるべきかを指定することが含まれます。

アクティブなコネクターの名前を見つける一つの方法は、xrandr --query を使用することです(これは Wayland でも機能します):

$ xrandr --query 
Screen 0: minimum 16 x 16, current 3840 x 2160, maximum 32767 x 32767
DP-1 connected primary 3840x2160+0+0 (normal left inverted right x axis y axis) 600mm x 340mm
   3840x2160     59.98*+
   2048x1536     59.95  
   ...
HDMI-A-1 connected 3840x2160+0+0 (normal left inverted right x axis y axis) 1440mm x 810mm
   3840x2160     59.98*+
   2048x1536     59.95  
   ...

正しいポートが識別されたら(例えばHDMI-A-1)、sysfs ポート名は ls -1d /sys/class/drm/card*-HDMI-A-1 を使用して見つけることができます(例えば card1-HDMI-A-1)。この場合、対応するディスプレイの EDID データは /sys/class/drm/card1-HDMI-A-1/edid に保持されます。

物理アドレスはこのようにプレビューできます:

$ edid-decode --physical-address /sys/class/drm/card1-DP-3/edid
4.0.0.0

cec デバイスノードが再作成されるたびに CEC 設定を行う必要があるため、これは cec オブジェクトが表示されたときに発火する別の udev ルールで最もよく処理されます。

ノート: 以下のルールで card1-HDMI-A-1 をあなたのコネクタ名に必ず置き換えてください。
/etc/udev/rules.d/cec-configure-autostart.rules
SUBSYSTEM=="cec" KERNEL=="cec0" ACTION=="add" TAG+="systemd" ENV{SYSTEMD_WANTS}="cec0-configure@card1-HDMI-A-1.service"
/etc/systemd/system/cec0-configure@.service
[Unit]
# Should be called as "cec0-configure@card1-HDMI-A-1.service" or similar
Description=Configure CEC adapter cec0 assuming it runs on output %i
AssertPathExists=/sys/class/drm/%i/edid
BindsTo=dev-cec0.device

[Service]  
Type=exec  
# --phys-addr-from-edid-poll checks EDID every tenth of a second
# https://git.linuxtv.org/v4l-utils.git/tree/utils/cec-ctl/cec-ctl.cpp?id=0a195181d771090f3c99d4a6ddb8151352509061#n1977
# Use `Type=oneshot` if using `--phys-addr-from-edid` instead
ExecStart=/usr/bin/cec-ctl --device=0 "--osd-name=%H" --playback "--phys-addr-from-edid-poll=/sys/class/drm/%i/edid"

HDMI ソースが自己を宣伝できるデバイスクラスには、「録画装置」(最大 3 台)、「チューナー」(最大 4 台)、「再生装置」(最大 3 台)の 3 種類があります。これは重要です。なぜなら、HDMI デバイスは CEC を介して互いに通信する際に物理アドレスを使用せず、代わりに 4 ビットの「論理アドレス」を使用して「チューナー#3」や「再生装置#1」などのデバイスを識別し、それぞれの数には限りがあるからです。一つのタイプのデバイスが多すぎるためにアドレス割り当てに失敗した場合、代わりに「バックアップ」(最大 2 台)の役割が割り当てられるかもしれません。これらの役割は、以前に述べた CEC の機能に関連して意図されています。すなわち:

  • 「チューナー」は「チューナーコントロール」をサポートすることが意図されています
  • 「録画装置」は、テレビが他のアドレスからの関連メッセージを無視するとされているため、ワンタッチレコードを使用できる唯一のタイプです
  • 「再生装置」は、一般的なビデオソース用です。コンピュータやビデオゲームコンソールなどは、「再生装置」とみなされます。

上記の cec0-configure@.service ユニットは --playback を使用して再生装置を設定しています。ただし、再生アドレスが使用済みでない場合、またはテレビの入力メニューで各デバイスクラスを視覚的に区別するために PC を目立たせたい場合は、デバイスクラスをチューナー(--tuner)またはレコーダー(--record)に設定しても一般的に問題ありません。

入力処理デーモン

ユーザー空間ツール

/dev/cec* デバイスへのユーザーアクセスは、ユーザーを video ユーザーグループに登録することで許可されます。CEC デバイスを制御する基本ツールは v4l-utils からの cec-ctl です。同様のものに libcec からの cec-client があり、python-cecAUR で利用可能な Python バインディングもあります。

参照