目次: ALSA
最近はPulseAudioがPipeWireに置き換わっているそうです。今はPulseAudioをリモートオーディオ再生機として使っているので、PipeWireで同じことをする方法を紹介します。
やりたいことはLinuxデスクトップからARM SBC上のPulseAudioへオーディオを飛ばすこと(2022年5月27日の日記参照)です。PulseAudioの場合はmodule-native-protocol-tcpを有効にして、TCPでオーディオを送るようにしました。
まずSinkデバイスの設定を行います。大抵HDMI、ヘッドフォン端子、あるいは別の出力端子があるはずですので、どこから音を鳴らすかを決めます。オーディオデバイスが1つしかない場合は設定不要かもしれませんが、一応チェックしておくと良いと思います。
設定にはWirePlumberの設定ツールwpctlを使います。wpctl statusで現在の様子を見ることができます。
$ wpctl status Audio ├─ Devices: │ 48. Built-in Audio [alsa] │ 49. Built-in Audio [alsa] │ 50. Built-in Audio [alsa] │ 51. Built-in Audio [alsa] │ ├─ Sinks: │ 35. Built-in Audio Stereo [vol: 1.00] │ 46. Built-in Audio Stereo [vol: 1.00] │ * 56. Built-in Audio Stereo [vol: 1.00] │ ├─ Sources: │ 44. Built-in Audio Stereo [vol: 1.00] │ * 57. Built-in Audio Stereo [vol: 1.00] │ ├─ Filters: │ └─ Streams:
SourcesとSinksのデフォルトデバイスを変更して、音声の入出力先を変更するにはset-defaultを使用します。wpctlはDevice、Source、Sinkの全てがユニークなIDを持っているので、SourceだとかSinkだとか指定する必要はなくて、IDのみ指定します。入出力先を変更後、もう一度statusを見るとSettingsの内容が変わるはずです。
例えば上記のstatusなら、set-defaultに指定できるのはSink系(35, 46, 56)かSource系(44, 57)のIDのうちどれか1つです。もし35か46か56を指定した場合は、IDからSinkデバイスだとわかるのでデフォルトSinkデバイスが変更されます。44か57を指定した場合はデフォルトSourceデバイスが変更されます。直感的じゃない、辛い……。
$ wpctl set-default 56 $ wpctl set-default 57 $ wpctl status ... Settings └─ Default Configured Devices: 0. Audio/Sink alsa_output.platform-es8316-sound.stereo-fallback 1. Audio/Source alsa_input.platform-es8316-sound.stereo-fallback
余談でWirePlumberが出てくる理由を紹介します。PipeWireは音声の入出力経路を管理しないため、PipeWire以外のソフトウェアをインストールして音声の経路管理しなければならないからです。WirePlumberもPipeWireもこだわりというか思想の強さがにじみ出ていて、私は仲良くなれなさそうです……。
動作確認は音を鳴らしてみて鳴れば方法は問いませんが、一例としてALSAを使った方法を紹介します。PipeWireとALSAやV4L2を繋ぐためのモジュールとalsa-utilsをインストールします。
$ sudo apt-get install pipewire-alsa pipewire-audio pipewire-v4l2 alsa-utils $ speaker-test -c 2 -r 48000 -D pipewire speaker-test 1.2.14 Playback device is pipewire Stream parameters are 48000Hz, S16_LE, 2 channels Using 16 octaves of pink noise Rate set to 48000Hz (requested 48000Hz) Buffer size range from 64 to 1048576 Period size range from 32 to 524288 Periods = 4 was set period_size = 12000 was set buffer_size = 48000 0 - Front Left
左右のスピーカーから交互にノイズ音(サーー)がなれば成功です。鳴らない場合は設定とボリューム(wpctlで確認できます)、もしくはALSAデバイス側のボリューム、ミュート設定の問題も有り得るので、alsamixerで確認してみてください。
次はPulseAudioモジュールの設定変更です。PipeWireと一緒にインストールされるはずですが、もし下記の設定ファイルが存在しなければpipewire-pulseをインストールしてください。
# /usr/share/pipewire/pipewire-pulse.conf ... pulse.properties = { # the addresses this server listens on server.address = [ "unix:native" #"unix:/tmp/something" # absolute paths may be used #★★この行を有効にする "tcp:4713" # IPv4 and IPv6 on all addresses #"tcp:[::]:9999" # IPv6 on all addresses #"tcp:127.0.0.1:8888" # IPv4 on a single address # #{ address = "tcp:4713" # address # max-clients = 64 # maximum number of clients # listen-backlog = 32 # backlog in the server listen queue # client.access = "restricted" # permissions for clients #} ] ...
$ systemctl --user restart pipewire-pulse
設定を変更したら再起動をお忘れなく。
#### クライアント側で操作 $ PULSE_SERVER=192.168.1.x speaker-test -c 2 -r 48000 -D pulse
リモートオーディオ再生のクライアント側でPULSE_SERVERにサーバーのIPアドレスを指定して音声を再生します。サーバー側から音が鳴れば成功です。
目次: Linux
Makefileの達人には常識かもしれませんが、makeがリンクを行うときのデフォルトルール(LINK.o)が使うコマンドはLDではなくCCです。私はリンク時にldが直接呼ばれるのは見たことがないにも関わらず、ずっとLDが使われると思いこんでいました。
話は以上で終わり……だとつまらないので、実験もしましょう。Makefileとコンパイラの代わりにスクリプトを呼びます。makeはGNU Make 4.4.1を使いました。
CC = ./cc-dummy CXX = ./cxx-dummy CPP = ./cpp-dummy LD = ./ld-dummy CFLAGS = cflags-dummy CXXFLAGS = cxxflags-dummy CPPFLAGS = cppflags-dummy LDFLAGS = ldflags-dummy LOADLIBES = loadlibes-dummy LDLIBS = ldlibs-dummy all: target-c target-cxx target-c: target-c.o target-cxx: target-cxx.o
$ cat ./cc-dummy #!/bin/sh touch target-c.o $ cat ./cxx-dummy #!/bin/sh touch target-cxx.o
コマンドが見つからないエラーを防ぐため、CCやCXXに指定した名前のスクリプトも作ります。スクリプトではコンパイラがオブジェクトファイル(*.o)を作成する動きのみを模しておけば十分です。
オブジェクトファイルの生成でデフォルトのコンパイルのルール、バイナリファイルの生成でリンクのルールが呼ばれます。このときCCやCXXが使われるか?LDが使われるか?がわかるはずです。実行します。
$ make #### C言語プログラムのコンパイルとリンク、どちらもCCを使う ./cc-dummy cflags-dummy cppflags-dummy -c -o target-c.o target-c.c ./cc-dummy ldflags-dummy target-c.o loadlibes-dummy ldlibs-dummy -o target-c #### C++言語プログラムのコンパイルとリンク、コンパイルはCXX、リンクはCCを使う ./cxx-dummy cxxflags-dummy cppflags-dummy -c -o target-cxx.o target-cxx.cc ./cc-dummy ldflags-dummy target-cxx.o loadlibes-dummy ldlibs-dummy -o target-cxx
C言語でもC++言語でもリンクは一緒で、CCを呼び出しました。LDは使われません。
オプション-pでmakeのデフォルトルールを見ることができます。"%: %.o"はオブジェクトファイルからバイナリを生成するときに当てはまるデフォルトルールです。コロンの左が生成ファイル、右が依存ファイルです。%はワイルドカードです。
UNIX系の慣例で、実行ファイル名は拡張子なし(例えばhoge)、オブジェクトファイル名は*.o(例えばhoge.o)にします。そのペアにうまく当てはまるルールになっています。
# デフォルト LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH) #...(略)... %: %.o # 実行するレシピ (ビルトイン): $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
当たり前ですが、実験で見た結果と一緒です。
GNU Makeのソースコードも眺めてみました。おそらくdefault.cがデフォルトルールの定義だと思います。デフォルトルールと一緒です。そりゃそうですね。
// make/src/default.c
static const char *default_variables[] =
{
#ifdef VMS
//...
#else /* !VMS */
//...
"LINK.o", "$(CC) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
"LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
"LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
//...
ソースコードを見て初めて知ったことが、VAX用のVMSというOSだとCCではなくLDを使うことです。しかし今の時代にVMS使っている人はいないでしょう……たぶん。
目次: Linux
以前、LinuxのI/O統計情報を得る/proc/[pid]/ioの実装を調べました。あのときは深追いしませんでしたが、/procには/proc/[pid]/以下のファイルから何が読めるのか、pid_entryの配列で指定する仕組みがありました。
// fs/proc/base.c
/*
* Thread groups
*/
static const struct pid_entry tgid_base_stuff[] = {
DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
//...
#ifdef CONFIG_TASK_IO_ACCOUNTING
ONE("io", S_IRUSR, proc_tgid_io_accounting), //★★★★これ
#endif
なぜこの配列に要素を足すと/proc/[pid]/以下のファイルが定義できるのでしょう?まずはopen/readに限定して調べてみます。調査対象はLinux-5.15です。
/proc/(tgid)/以下のファイルを定義しているtgid_base_stuffの中身は、DIR()もしくはONE()マクロを使って定義します。ONE()マクロを見てみます。
// fs/proc/base.c
#define ONE(NAME, MODE, show) \
NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_single_file_operations, \
{ .proc_show = show } )
#define NOD(NAME, MODE, IOP, FOP, OP) { \
.name = (NAME), \
.len = sizeof(NAME) - 1, \
.mode = MODE, \
.iop = IOP, \
.fop = FOP, \
.op = OP, \
}
ネストしたマクロはわかりにくいです。何か1つ(ここではio)を展開すると多少はわかりやすいと思います。
// fs/proc/base.c
// ★★★★NODを展開
#define ONE(NAME, MODE, show) { \
.name = (NAME), \
.len = sizeof(NAME) - 1, \
.mode = (S_IFREG|(MODE)), \
.iop = NULL, \
.fop = &proc_single_file_operations, \
.op = { .proc_show = show }, \
}
static const struct file_operations proc_single_file_operations = {
.open = proc_single_open, //★★open時に呼ばれる関数
.read = seq_read, //★★read時に呼ばれる関数
.llseek = seq_lseek,
.release = single_release,
};
// ★★★★ioの定義を当てはめる
ONE("io", S_IRUSR, proc_tgid_io_accounting),
#define ONE(NAME, MODE, show) { \
.name = ("io"), \
.len = sizeof("io") - 1, \
.mode = (S_IFREG|(S_IRUSR)), \
.iop = NULL, \
.fop = &proc_single_file_operations, \
.op = { .proc_show = proc_tgid_io_accounting }, \
}
ファイルopen時にproc_single_open()、read時にseq_read()が呼ばれるように、あとはop.proc_showにproc_tgid_io_accounting()を指定しています。
どうやってproc_single_open()が呼ばれるか?は一旦無視して、open時に呼ばれるものとして調べます。
// linux/fs/proc/base.c
static int proc_single_open(struct inode *inode, struct file *filp)
{
return single_open(filp, proc_single_show, inode);
}
// linux/fs/seq_file.c
int single_open(struct file *file, int (*show)(struct seq_file *, void *),
void *data)
{
struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL_ACCOUNT);
int res = -ENOMEM;
if (op) {
op->start = single_start;
op->next = single_next;
op->stop = single_stop;
op->show = show; //★★show = proc_single_show()
res = seq_open(file, op);
if (!res)
((struct seq_file *)file->private_data)->private = data;
else
kfree(op);
}
return res;
}
EXPORT_SYMBOL(single_open);
int seq_open(struct file *file, const struct seq_operations *op)
{
struct seq_file *p;
WARN_ON(file->private_data);
p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL);
if (!p)
return -ENOMEM;
file->private_data = p;
mutex_init(&p->lock);
p->op = op; //★★op = struct seq_operations, op->show = proc_single_show()
// No refcounting: the lifetime of 'p' is constrained
// to the lifetime of the file.
p->file = file;
/*
* seq_files support lseek() and pread(). They do not implement
* write() at all, but we clear FMODE_PWRITE here for historical
* reasons.
*
* If a client of seq_files a) implements file.write() and b) wishes to
* support pwrite() then that client will need to implement its own
* file.open() which calls seq_open() and then sets FMODE_PWRITE.
*/
file->f_mode &= ~FMODE_PWRITE;
return 0;
}
EXPORT_SYMBOL(seq_open);
ここで出てくるseq_で始まる関数群とsingle_で始まる関数群は、seq_fileと呼ばれる仕組み(The seq_file interface - The Linux Kernel Documentation)です。変な名前だなあ?と思うのはごもっともですけど正式名称なのです……。
仮想ファイルシステム上にファイルを定義するときは、openやreadを実装しなければなりません。特にread()の実装は曲者で読み出し位置の管理が面倒です。しかしseq_fileを使うと内部にバッファを勝手に確保し、読み出し位置を管理してくれます。もっとも簡単な実装だと、seq_printf()で内部バッファに書き出すだけで済みます。/procのような何か情報を返すファイルシステムを実装するときに便利です。
次にread時の動作を見ます。open同様にどうやってseq_read()が呼ばれるか?は一旦無視して、read時に呼ばれるものとして調べます。
// linux/fs/seq_file.c
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
struct iovec iov = { .iov_base = buf, .iov_len = size};
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, file);
iov_iter_init(&iter, READ, &iov, 1, size);
kiocb.ki_pos = *ppos;
ret = seq_read_iter(&kiocb, &iter); //★★★★
*ppos = kiocb.ki_pos;
return ret;
}
EXPORT_SYMBOL(seq_read);
ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
struct seq_file *m = iocb->ki_filp->private_data;
size_t copied = 0;
size_t n;
void *p;
int err = 0;
//...略...
// get a non-empty record in the buffer
m->from = 0;
p = m->op->start(m, &m->index);
while (1) {
err = PTR_ERR(p);
if (!p || IS_ERR(p)) // EOF or an error
break;
err = m->op->show(m, p); //★★ここでshow = proc_single_show()を呼ぶ
if (err < 0) // hard error
break;
if (unlikely(err)) // ->show() says "skip it"
m->count = 0;
if (unlikely(!m->count)) { // empty record
p = m->op->next(m, p, &m->index);
continue;
}
if (!seq_has_overflowed(m)) // got it
goto Fill;
// need a bigger buffer
m->op->stop(m, p);
kvfree(m->buf);
m->count = 0;
m->buf = seq_buf_alloc(m->size <<= 1);
if (!m->buf)
goto Enomem;
p = m->op->start(m, &m->index);
}
// EOF or an error
m->op->stop(m, p);
m->count = 0;
goto Done;
//...略...
// linux/fs/proc/base.c
static int proc_single_show(struct seq_file *m, void *v)
{
struct inode *inode = m->private;
struct pid_namespace *ns = proc_pid_ns(inode->i_sb);
struct pid *pid = proc_pid(inode);
struct task_struct *task;
int ret;
task = get_pid_task(pid, PIDTYPE_PID);
if (!task)
return -ESRCH;
ret = PROC_I(inode)->op.proc_show(m, ns, pid, task); //★★ここでproc_show = proc_tgid_io_accounting()を呼ぶ
put_task_struct(task);
return ret;
}
やっとONE()に渡したproc_tgid_io_accountingが呼ばれる場所がわかりました。長かった……。
目次: Linux
いつも忘れるudevの使い方メモです。udevadmでデバイス属性を調べる方法です。
$ sudo udevadm info --attribute-walk /dev/video0 Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:08.1/0000:07:00.3/usb3/3-3/3-3.1/3-3.1:1.0/video4linux/video0': KERNEL=="video0" SUBSYSTEM=="video4linux" DRIVER=="" ATTR{dev_debug}=="0" ATTR{index}=="0" ATTR{name}=="USB 2.0 Camera: USB 2.0 Camera" ATTR{power/async}=="disabled" ATTR{power/control}=="auto" ATTR{power/runtime_active_kids}=="0" ATTR{power/runtime_active_time}=="0" ATTR{power/runtime_enabled}=="disabled" ATTR{power/runtime_status}=="unsupported" ATTR{power/runtime_suspended_time}=="0" ATTR{power/runtime_usage}=="0" looking at parent device '/devices/pci0000:00/0000:00:08.1/0000:07:00.3/usb3/3-3/3-3.1/3-3.1:1.0': KERNELS=="3-3.1:1.0" SUBSYSTEMS=="usb" DRIVERS=="uvcvideo" ATTRS{authorized}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceClass}=="0e" ATTRS{bInterfaceNumber}=="00" ATTRS{bInterfaceProtocol}=="00" ATTRS{bInterfaceSubClass}=="01" ATTRS{bNumEndpoints}=="01" ATTRS{iad_bFirstInterface}=="00" ATTRS{iad_bFunctionClass}=="0e" ATTRS{iad_bFunctionProtocol}=="00" ATTRS{iad_bFunctionSubClass}=="03" ATTRS{iad_bInterfaceCount}=="02" ATTRS{interface}=="USB 2.0 Camera" ATTRS{power/async}=="enabled" ATTRS{supports_autosuspend}=="1" ...
調べた属性をudevのrulesに書くときは、そのままATTRS{AAA}=="00"のように書けば良いです。他の例や詳細については、Arch Linuxのドキュメント(udev - ArchWiki)がとても詳しいです。
目次: Linux
V4L2(Video for Linux 2)は多才で全ての機能は知らないんですが、最低限の動作確認(デバイス一覧、フォーマット一覧、キャプチャ)を紹介します。ツールはvl42-ctlを使います。
$ sudo apt-get install v4l-utils
Debian系であればv4l-utilsパッケージに入っています。
デバイスの一覧を見るにはlist-devicesを、フォーマットの一覧を見るにはlist-formats-extを使います。
$ v4l2-ctl --list-devices USB 2.0 Camera: USB 2.0 Camera (usb-0000:07:00.3-3.1): /dev/video0 /dev/video1 /dev/media0
$ v4l2-ctl -d /dev/video0 --list-formats-ext ioctl: VIDIOC_ENUM_FMT Type: Video Capture [0]: 'MJPG' (Motion-JPEG, compressed) Size: Discrete 1920x1080 Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.200s (5.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 1280x800 Interval: Discrete 0.033s (30.000 fps) Size: Discrete 1280x720 Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.067s (15.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 800x600 Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.067s (15.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) ... [1]: 'YUYV' (YUYV 4:2:2) Size: Discrete 1920x1080 Interval: Discrete 0.200s (5.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 1280x800 Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 1280x720 Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 800x600 Interval: Discrete 0.067s (15.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) ...
この一覧に出てくる組み合わせを次のフォーマット設定で使いますので、どこかにメモしておきます。
取得したい画像サイズとフォーマットの組み合わせをデバイスに指定します。例では1920x1080のMotion JPEG(MJPG)を指定していますが、お使いのカメラに合わせて適宜変えてください。
$ v4l2-ctl -d /dev/video0 -V Format Video Capture: Width/Height : 1920/1080 Pixel Format : 'YUYV' (YUYV 4:2:2) Field : None Bytes per Line : 3840 Size Image : 4147200 Colorspace : sRGB Transfer Function : Rec. 709 YCbCr/HSV Encoding: ITU-R 601 Quantization : Default (maps to Limited Range) Flags : $ v4l2-ctl -d /dev/video0 -v width=1920,height=1080,pixelformat=MJPG $ v4l2-ctl -d /dev/video0 -V --get-fmt-video Format Video Capture: Width/Height : 1920/1080 Pixel Format : 'MJPG' (Motion-JPEG) Field : None Bytes per Line : 0 Size Image : 4147789 Colorspace : sRGB Transfer Function : Default (maps to sRGB) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Full Range) Flags :
フォーマット設定後は-Vでフォーマット取得して、意図通りに設定されたか確認することをお勧めします。特にフレームサイズは間違って変な値を指定しても(幅1920のつもりで幅192と書いた、など)、エラーにならず近しい設定が選ばれていることがあります。
キャプチャしてファイルに書き出すにはstream-toを使います。stream-countでフレーム数を100フレームにしています(100フレームキャプチャしたら終了)。フレーム数を指定しないと永遠にキャプチャし続けますが、適当なところでCtrl-cで止めればOKです。
$ v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=100 --stream-to=test.mjpg <<<<<<<<<<<<<<<<<<<< 19.84 fps, dropped buffers: 1 <<<<<<<<<<<<<<<<<<<< 19.88 fps <<<<<<<<<<<<<<<<<<<< 19.92 fps <<<<<<<<<<<<<<<<<<<< 19.94 fps <<<<<<<<<<<<<<<<<<<< 19.95 fps
再生は何を使っても良いですが、ffplayを使った例をご紹介します。
#### MJPGの場合 $ v4l2-ctl -d /dev/video0 -v width=1920,height=1080,pixelformat=MJPG $ v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=100 --stream-to=test.mjpg $ ffplay -framerate 20 test.mjpg #### YUYVの場合 $ v4l2-ctl -d /dev/video0 -v width=1920,height=1080,pixelformat=YUYV $ v4l2-ctl -d /dev/video0 --stream-mmap=3 --stream-count=25 --stream-to=test.raw $ ffplay -f rawvideo -video_size 1920x1080 -pixel_format yuyv422 -framerate 5 test.raw
フレームレートの指定(framerate)はカメラの性能に合わせて適宜変更してください。
目次: Linux
Debian TestingなデスクトップPCをapt-get upgradeしたら、またxrdpが動かなくなりました。以前(2024年12月2日の日記参照)と同じ原因のようです。ログファイル~/.xorgxrdp.10.logを見るとX.orgがクラッシュしています。
[ 2251.652] (EE) Backtrace: [ 2251.653] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.653] (EE) 0: /usr/lib/xorg/Xorg (?+0x0) [0x56196ae0bf6d] [ 2251.654] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.654] (EE) 1: /lib/x86_64-linux-gnu/libc.so.6 (?+0x0) [0x7f62f1534df0] [ 2251.654] (EE) 2: /lib/x86_64-linux-gnu/libc.so.6 (__pthread_kill_implementation+0x10c) [0x7f62f158995c] [ 2251.654] (EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (__GI_raise+0x12) [0x7f62f1534cc2] [ 2251.655] (EE) 4: /lib/x86_64-linux-gnu/libc.so.6 (__GI_abort+0x22) [0x7f62f151d4ac] [ 2251.655] (EE) 5: /lib/x86_64-linux-gnu/libc.so.6 (__libc_message_impl.cold+0x5) [0x7f62f151e291] [ 2251.655] (EE) 6: /lib/x86_64-linux-gnu/libc.so.6 (malloc_printerr+0x15) [0x7f62f1593465] [ 2251.656] (EE) 7: /lib/x86_64-linux-gnu/libc.so.6 (munmap_chunk+0x7c) [0x7f62f15936ec] [ 2251.656] (EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__free+0x158) [0x7f62f1598398] [ 2251.656] (EE) 9: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevice+0x7d) [0x7f62f1a2a13d] [ 2251.657] (EE) 10: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevices+0x2e) [0x7f62f1a2a2ae] [ 2251.657] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.657] (EE) 11: /lib/x86_64-linux-gnu/libnvidia-egl-gbm.so.1 (?+0x0) [0x7f62f0968f38] [ 2251.657] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.657] (EE) 12: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (?+0x0) [0x7f62f06adcb0] [ 2251.657] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.657] (EE) 13: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (?+0x0) [0x7f62f064cd9c] [ 2251.657] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.658] (EE) 14: /lib/x86_64-linux-gnu/libEGL.so.1 (?+0x0) [0x7f62f0a5aad5] [ 2251.658] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.658] (EE) 15: /usr/lib/x86_64-linux-gnu/dri/swrast_dri.so (?+0x0) [0x7f62f0a9d3f3] [ 2251.658] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.658] (EE) 16: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f62f11cdc73] [ 2251.658] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.658] (EE) 17: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f62f11ccadf] [ 2251.658] (EE) 18: /usr/lib/xorg/Xorg (_CallCallbacks+0x3c) [0x56196ac941cc] [ 2251.658] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.658] (EE) 19: /usr/lib/xorg/Xorg (?+0x0) [0x56196adc64ef] [ 2251.659] (EE) 20: /usr/lib/xorg/Xorg (InitExtensions+0x89) [0x56196ad01d29] [ 2251.659] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 2251.659] (EE) 21: /usr/lib/xorg/Xorg (?+0x0) [0x56196ac92ae8] [ 2251.659] (EE) 22: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_call_main+0x78) [0x7f62f151eca8] [ 2251.659] (EE) 23: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main_alias_2+0x85) [0x7f62f151ed65] [ 2251.659] (EE) 24: /usr/lib/xorg/Xorg (_start+0x21) [0x56196ac7b641] [ 2251.659] (EE) [ 2251.659] (EE) Fatal server error: [ 2251.659] (EE) Caught signal 6 (Aborted). Server aborting
# mv /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 /lib/x86_64-linux-gnu/libEGL_nvidia.so.01
クラッシュしている個所は前回と若干違います。Xorgは起動処理らしき関数(InitExtensions)を呼んでいて、libEGL_nvidia.so.0は終了処理らしき関数(drmFreeDevice)を呼んでいます。おそらく何かエラーが起きていると思いますが、NVIDIAのライブラリはバイナリしか提供されていないので調査不能です。前回同様にlibEGL_nvidia.soをリネームor削除すれば起動します。
前回と同じ直し方で直します。カーネルが入れ替わっているので、古いカーネルヘッダ(linux-headers-6.11.10-amd64)を削除して新しいカーネルヘッダ(linux-headers-6.16.8+deb14-amd64)をインストールします。
次にsudo dpkg-reconfigure nvidia-kernel-dkmsを実行するとNVIDIA系の*.koファイルがビルドされるので、modprobe nvidia-drmでロードします。もしカーネルヘッダの選択を間違っていたら、modprobe時にエラーになるのでわかるはずです。
NVIDIAのドライバはカーネルが変わるたびに毎回ビルドしなおさなければいけないんでしょうか?面倒だな〜。
< | 2025 | > | ||||
<< | < | 10 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | 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 | - |
合計:
本日: