HDMI-CEC
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など)が画像との遅延補償に使用できます。
PC のようなデバイスにとって、これらの中で最も有用なのは「リモートコントロールパススルー」でしょう。HTPC にとっては「システムスタンバイ」が有用かもしれませんが、スクリーンがオフになったときに通常スリープ状態に入ることが期待されないより一般的な用途のマシンでは疑問の余地があります。「ルーティングコントロール」は、テレビがその入力を表示しようとするときにシステムを起動させるために使用できますが、接続されたPCがサスペンド中にCECトラフィックをリッスンする方法を持っている場合に限ります。「システムオーディオコントロール」は、一部の HDMI サウンド出力にとって便利ですが、現在、PipeWireや PulseAudio といったもので音量制御の手段としては機能していません。
ハードウェアセットアップ
Linux のカーネルには既に CEC イベントに自動的に応答し、処理するための組み込みのサブシステムがありますが、ハードウェアが正しく機能するためには最初に設定が必要になる場合があります。
Native CEC
Native CEC は主に ARM デバイスで見られます。x86 世界では、DisplayPort経由のトンネリングが最も簡単なオプションです。それ以外では、一部の Chrome OS デバイスと SECO UDOO のシングルボードコンピューターのみが CEC を提供しています。
DisplayPort 経由のトンネリング
これは i915、nouveau、amdgpu ドライバーで機能します。2014 年に導入された DisplayPort 1.3 標準では、DisplayPort から HDMI アダプターを使用して補助チャネルを介して CEC 信号を双方向に転送することができます。これはアダプターが通常サポートしていない種類の機能であり、一般的ではありませんが、USB-CEC アダプターよりも直感に反して CEC のトンネリングを DisplayPort 経由で使用する方が安価で簡単な場合があります。CEC サブモジュールのカーネルドキュメントページには、動作が確認されたアダプターのリストがあります。
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 パッケージが必要です。
/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 ルールで最もよく処理されます。
/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 バインディングもあります。
参照
- CEC サブシステムに関するカーネルドキュメント
- HDMI 上の CEC (Consumer Electronics Control)、Embedded Linux Wiki (eLinux.org)内
- HDMI CEC: 何? なぜ? どうやって?、CEC サブシステムの大部分を書いた Hans Verkuil による
- CEC-O-Matic、生の CEC メッセージを作成し、有効な CEC フレームを構成するものの概要を提供するツール