跳转至内容

Xorg 多座位

来自 ArchWiki

本文章或章节需要扩充。

原因: 展示如何配置 PulseAudio 以支持多个用户,而无需全局运行 PulseAudio。解释如何仅使用一个显卡(和/或 X 服务器)以及不使用 Xephyr 来实现多座位。(在 Talk:Xorg multiseat 中讨论)

本文或本节需要在语言、wiki 语法或风格方面进行改进。请参阅 Help:Style 获取参考。

原因: 以第一人称写作,更像是一篇博客文章。(在 Talk:Xorg multiseat 中讨论)

多座位是一种特定的设置,其中 N 个用户同时在一台计算机上工作。这是通过 N 个显示器、N 个键盘和 N 个鼠标来实现的。其优点显而易见:

  • 更低的功耗(仅一台计算机)
  • 更少的硬件购买成本

需求

本文或本章节已过时。

原因: 此部分引用了过时的硬件(PS/2 键盘、AGP 或 PCI GPU、10k RPM 硬盘等),自 2007 年以来内容未进行重大更新:这对于当前一代硬件是否仍然相关?(在 Talk:Xorg multiseat 中讨论)

键盘和鼠标

任何标准的 PS/2 或 USB 键盘都可以。鼠标也是一样。

显卡硬件

为了获得最佳效果,您需要两块显卡。我曾使用过一块 nVidia FX5500 AGP 和一块 nVidia 6200 PCI。如果您稍微留意一下,肯定能以较低的价格找到新的、不错的 PCI 显卡。

可以使用只有一个双头输出的显卡(大多数 nvidia 显卡都具备),但这有一些限制:您必须在第二个显示器上使用 Xephyr,根据我的阅读,这似乎是一个很麻烦的解决方案,并且为了最佳使用,两个屏幕都需要相同的分辨率。

如果您有两个 PCI-Express 插槽,请充分利用它们!这样您甚至可以同时玩两个游戏。(PCI 太慢,无法舒适地玩游戏)

处理器和内存

如果您确实需要让两个用户在同一台计算机上工作,我至少会推荐一款双核处理器和充足的内存。为获得舒适的使用体验,建议使用快速的硬盘(10,000 RPM 或更高)。

软件

您需要 Xorg 以及显卡驱动程序(根据一些来源,闭源的 nvidia 驱动程序比开源的 nvidia 驱动程序在此方面表现更好,我没有亲自测试过)和 evdev(xf86-input-evdev)驱动程序。仅此而已。所有这些都可以在 Arch Linux 的 core 和 extra 仓库中找到。

一些 X 知识

如果您了解 X 的工作原理,这将更容易。在开始之前,建议使用 xorg.conf(5) 生成一个适用于单屏幕的干净配置。通读此 xorg 配置,并使其熟悉。一如既往,man 手册页将为您提供大部分答案。您可以参考一些 man 手册页:Xorg(1)Xserver(1)startx(1)xdm(8)xinit(1)

您还可以查看以下命令的输出以获得一些提示

# X -configure
# X -showopts

定义

为了使本文清晰,我将使用以下定义:

  • 屏幕:屏幕是 Xorg 可以显示其内容的区域。屏幕分配有一个显示器和一个显卡。
  • 显示器:物理显示器,就像您现在看到的那个。
  • 服务器布局:定义要使用的屏幕、键盘和鼠标。
  • 座位:一个工作区,包含一个物理显示器、一个物理键盘和一个物理鼠标。

技巧与提示

  • 在您的计算机上设置 ssh,以便您可以从另一台计算机(例如笔记本电脑)SSH 到该机器。这非常有用,因为您可能会遇到 X 无响应或根本没有显示的情况。
  • 找出哪个键盘和鼠标是哪个:打开一个终端并使用 cat 来查找。例如,cat /dev/input/mouse1。如果您移动鼠标并看到所有奇怪的事情发生,那么那就是您正在移动的鼠标。键盘也一样,它们被称为 eventN。
  • 首先尝试一个基本配置。不要从花哨的东西开始,先让一个非常基础的 Xorg 工作起来。
  • 创建所有相关配置文件备份。您打算跳过这一项吗?

关于 evdev

evdev 是一个 Xorg 驱动程序,可以利用内核事件设备,您可以在 /dev/input 中找到它们。

将设备附加到座位

systemd 的 loginctl(1) 允许您通过创建 udev 规则将设备分配给座位。

识别设备

查看默认座位 (seat0) 状态,这是一个例子

# loginctl seat-status seat0
seat0
        Sessions: *11
         Devices:
                  ├ /sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0/drm/card0
                  │ (drm:card0)
                  ├ /sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0/graphics/fb0
                  │ (graphics:fb0) "radeondrmfb"
                  ├ /sys/devices/pci0000:00/0000:00:02.0/0000:03:00.1/sound/card1
                  │ (sound:card1) "Generic"
                  │ └ /sys/devices/pci0000:00/0000:00:02.0/0000:03:00.1/sound/card1/input15
                  │   (input:input15) "HD-Audio Generic HDMI/DP,pcm=3"
                  ├ /sys/devices/pci0000:00/0000:00:12.0/usb3
                  │ (usb:usb3)
                  │ ├ /sys/devices/pci0000:00/0000:00:12.0/usb3/3-1/3-1:1.2/0003:046D:C52B.0006/input/input5
                  │ │ (input:input5) "Logitech Unifying Device. Wireless PID:101b"
                  │ └ /sys/devices/pci0000:00/0000:00:12.0/usb3/3-1/3-1:1.2/0003:046D:C52B.0006/input/input6
                  │   (input:input6) "Logitech Unifying Device. Wireless PID:200a"
                  ├ /sys/devices/pci0000:00/0000:00:14.2/sound/card0
                  │ (sound:card0) "SB"
                  │ ├ /sys/devices/pci0000:00/0000:00:14.2/sound/card0/input7
                  │ │ (input:input7) "HDA ATI SB Line"
                  │ └ /sys/devices/pci0000:00/0000:00:14.2/sound/card0/input9
                  │   (input:input9) "HDA ATI SB Rear Mic"
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/drm/card1
                  │ (drm:card1)
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/graphics/fb1
                  │ (graphics:fb1) "radeondrmfb"
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.1/sound/card2
                  │ (sound:card2) "HDMI"
                  │ └ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.1/sound/card2/input16
                  │   (input:input16) "HDA ATI HDMI HDMI/DP,pcm=3"
                  ├ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0/input/input2
                  │ (input:input2) "CHESEN PS2 to USB Converter"
                  ├ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.1/input/input3
                  │ (input:input3) "CHESEN PS2 to USB Converter"
                  └ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-2/4-2:1.0/input/input4
                    (input:input4) "Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)"

如果不确定,请尝试与 lspcilsusb 进行比较以识别设备。

分配设备

座位是根据显卡创建的。因此,我们将从分配显卡开始。

# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/drm/card1
# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/graphics/fb1

然后添加输入设备。第一个示例(不推荐)通过上面的列表按端口和子设备添加了三个 USB 设备。

# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0/input/input2
# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.1/input/input3
# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.1/usb4/4-2/4-2:1.0/input/input4

这不太理想,因为用另一个键盘替换会仅在新的键盘包含相同的子设备(1.01.1)时才有效,并且如果键盘和鼠标意外地插反了 USB 端口,它们将不会被分配到预期的座位,并会回到默认的 seat0。更灵活的方法是而是将一个特定的 USB 端口添加到座位,允许插入该 USB 端口的任何设备被分配到该座位(键盘、鼠标、USB 声卡等)。这里,两个 USB 端口被分配到该座位,您可以看到它来自上面的同一列表,只是末尾部分被删除了。

# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1
# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.1/usb4/4-2

使用多个声卡,您可以为每个座位分配一个,这将开箱即用地支持每个用户会话的 PulseAudio

# loginctl attach seat1 /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.1/sound/card2

您应该能够看到硬件被划分为两个座位。

# loginctl seat-status seat0
# loginctl seat-status seat1

座位名称只是字符串标签,所以您可以随意命名座位 - seat-1seatleftseat-tv 都是有效的名称。虽然您不必使用 seat 前缀,但不建议这样做,因为某些程序(例如 LightDM)仅将其默认选项应用于匹配 seat* 表达式的座位,因此任何不以 seat 开头的名称可能需要额外的手动配置。seat0 是默认座位名称,无法更改。

任何未明确标记到座位的设备最终都会进入 seat0。如果一个设备被标记到给定的座位,那么所有子设备也属于该座位。这对于热插拔接口非常有用,例如上面的示例,它将 USB 端口分配给特定的座位,因此插入这些端口的任何设备都将自动继承 USB 端口本身上设置的座位。

loginctl attach 会创建和删除与 /etc/udev/rules.d/72-seat-*.rules 匹配的 udev 规则文件,因此如果您希望备份座位配置,这些就是需要保存和恢复的文件。

每个座位在出现标记为 master-of-seat 的设备之前不会显示为就绪。默认的 udev 规则会自动将此标签应用于任何 drmgraphics 设备。因此,如果您不将这些设备之一作为座位的一部分(例如,只有键盘和音频的视障用户),那么 loginctl 创建的 udev 规则将需要手动编辑,并在此标签指定后,座位才能使用。请参阅默认的 udev 规则以获取示例。

设置 Xorg

由于您可以使用 loginctl 将设备附加到座位,因此无需特定的 Xorg 配置,因此如果您通过 loginctl 附加了设备,可以跳过创建 Xorg 配置文件。另请注意,将 ServerFlags "AutoAdd*" 选项设置为 false 会强制 Xorg 忽略大多数 loginctl 附加。

如果您确实选择使用自定义 Xorg 配置(例如,您有一块 nVidia 卡并希望设置高级显示选项),那么过程与通常情况基本相同,主要区别在于您为每个座位定义一个 ServerLayout 部分,并在每个服务器布局中包含 MatchSeat 语句以指示它应应用于哪个座位。您还可以将 MatchSeat 指令应用于图形设备和显示器本身,以避免定义 ServerLayout,如果您不需要任何 ServerLayout 功能。请注意,任何缺少 MatchSeat 指令的部分都将对所有服务器布局和座位可见,因此请确保配置的其他部分可防止多个座位尝试访问同一设备。(一个常见的错误是允许两个座位访问同一显示设备,这将导致一个座位工作而其他座位启动失败。)

以下是一个此类型手动配置的示例。您可以创建部分或全部配置集,用于两个服务器布局,每个布局都分配有自己的键盘、鼠标、显卡和显示器。如果您省略了某一部分(例如 InputDevice 部分),则将应用 Xorg 默认设置。

xorg.conf.d tree example:
├── 00-keyboard.conf   #created by localectl
├── 31-monitor-seat0.conf
├── 32-monitor-seat1.conf
├── 40-serverflags.conf
├── 41-graphic-seat0.conf
├── 42-graphic-seat1.conf
├── 51-screen-seat0.conf
├── 52-screen-seat1.conf
├── 61-layout-seat0.conf
└── 62-layout-seat1.conf

定义可用的输入设备

配置的这一部分告诉 Xorg 可用的输入设备。输入设备包括键盘和鼠标,但也可以是触摸屏和画笔等。

按照 Xorg#输入设备 中的说明配置您的设备。“Identifier”将允许您分配给 ServerLayout,“Device”定义您正在配置的物理设备。

01-keyboard-seat0.conf
Section "InputDevice"
        Identifier      "keyboard0"
        Option          "Device"                "/dev/input/event1"
        #Option          "Device"                "/dev/input/by-path/pci-0000:00:1a.0-usb-0:1.6:1.0-event-kbd"  # or by path

        # GrabDevice no longer has any effect: https://www.spinics.net/lists/xorg/msg59881.html
        Option "GrabDevice" "on" # prevent send event to other X-servers
EndSection

其他 输入设备 也一样。

显示器

按照 Xorg#显示器设置 中的说明配置您的显示器。请密切关注标识符。

31-monitor-seat0.conf
Section "Monitor"
    Identifier             "monitor0"
EndSection

ServerFlags

40-serverflags.conf
Section "ServerFlags"
        Option "AutoAddGPU" "off"
EndSection

显卡

仔细查看 BusID。此选项指定要使用的硬件卡。您可以使用 lspci 找出 BusId。但是,您很快会发现这并不总是匹配。这是因为 lspci 以十六进制形式显示设备地址。而 Xorg 使用十进制形式。因此,您需要将地址从十六进制转换为十进制。因此,lspci 中的设备地址 0:0a:0 将在 xorg.conf 中变为 0:10:0。

42-graphic-seat1.conf
Section "Device"
        Identifier      "graphic0"
        Driver          "nvidia"
        Option          "NoLogo"                "1"  # Remove nvidia branding at startup
        BusId           "PCI:1:0:0"
        MatchSeat       "seat-1"                     # Needed when only configuring part of Xorg for non-seat0.
        Option          "Monitor-DVI-1"         "monitor1"  #assigns monitor configuration to graphic output port
EndSection

另一个更高级的示例,使用了 nVidia TwinView,因此一个座位有两个显示器,一个显示器是横向的,另一个是纵向的。

42-graphic-seat-nvidia.conf
Section "Device"
        Identifier "nvidia"
        Driver "nvidia"
        BusID "PCI:66:0:0"  # lspci reports this as 42:00.0, so 42 hex is 66 decimal

        # See the nVidia documentation for what these options do.  They of
        # course only apply if you have an nVidia card and you are using their
        # closed-source driver.
        Option "UseDisplayDevice" "DP-3"
        Option "MetaModes" "DP-3: 2560x1600, DP-0: 1600x1200 { Rotation=left }"
        Option "TwinViewOrientation" "LeftOf"

        # Not needed, avoid errors in logs
        Option "ConnectToAcpid" "false"

        # Do not automatically set the DPI based on screen size, use the traditional
        # value to avoid fonts becoming overly large.
        Option "UseEdidDpi" "False"
        Option "DPI" "96 x 96"

        # No MatchSeat option is needed here if it's given in the ServerLayout instead.
        #Option "MatchSeat" "seat-nvidia"
EndSection

屏幕

请密切关注“monitor”选项。

51-screen-seat0.conf
Section "Screen"
        Identifier              "screen0"
        Device                  "graphic0"
        Monitor                 "monitor0"
        DefaultDepth    24
        Subsection "Display"
                Depth   24
                Modes   "1280x1024"     "1024x768"
        EndSubsection
EndSection

ServerLayout

为每个座位创建一个部分(注意 Identifier),并包含各自的键盘、鼠标和屏幕。

62-layout-seat1.conf
Section "ServerLayout"
        # The Identifier is not really important but must be unique.
        Identifier      "seat-1"

        # This controls which Screen section is used in the layout, which in turn
        # dictates which GPU and monitor will be used.  The numbers can be omitted
        # if only one Screen is used (normally the case unless you are combining
        # monitors from different video cards).
        Screen          "screen1"       0                   0

        # InputDevice sections can usually be omitted
        InputDevice     "mouse1"        "CorePointer"
        InputDevice     "keyboard1"     "CoreKeyboard"

        Option          "SingleCard" "on"   # use this to simplfied isolatedevice option

        # MatchSeat means this layout will only be used when the "-seat seat-1"
        # parameter is given to /usr/bin/X, which most display managers will do
        # automatically.
        MatchSeat       "seat-1"
EndSection

额外提示

  • 在进行初始重启之前,请确保删除各个用户目录下的 ~/.Xauthority 文件。
  • 为避免撕裂,这似乎在几乎所有配置上都有帮助 - 将此添加到 /etc/environment
CLUTTER_PAINT=disable-clipped-redraws:disable-culling
CLUTTER_VBLANK=True

测试

在我们开始修改登录管理器之前,我们将首先测试各个座位。如果它们正常工作,那么我们就准备就绪了。

我使用了 twm(tiny window manager)来测试我的座位是否工作,但没有理由您不能使用 KDE、gnome 或任何其他桌面环境或窗口管理器。我在我的 ~/.xinitrc 中使用了这个:

exec twm

使用以下命令测试单个座位:

startx -- -layout seat0 -config xorg.conf.multiseat

对您拥有的每个座位都这样做。如果它们都工作正常,并且键盘/鼠标组合匹配,那么恭喜!您几乎完成了!如果您想知道我为什么没有使用我的新配置文件,那是因为 X 在以非 root 用户运行时不允许这样做。它会搜索 /etc/X11 相对于的 xorg.conf.multiseat。

设置登录管理器

本文章或章节需要扩充。

原因: 需要 SDDM 的说明。(在 Talk:Xorg multiseat 中讨论)

对于 XDM

打开 /etc/X11/xdm/Xservers 并设置以下变量(此示例演示了两个座位):

# NOTE: do not add -sharevts on seat0, otherwise it may reset in about 10~20 minutes automatically.
:0 local /usr/bin/X :0 vt07 -nolisten tcp  -novtswitch -layout seat0 -seat seat0
:1 local /usr/bin/X :1 vt08 -nolisten tcp -novtswitch -layout seat-1 -seat seat-1
注意 如果 XDM 未正确将座位编号分配给会话(loginctl 会显示一个没有座位的会话),那么您附加的设备可能会出现奇怪的行为,例如权限不足、PulseAudio 未检测到声卡…… LightDM 应该没问题。

另外,如果您使用 Arch Linux 主题,请为每个屏幕编辑 /etc/X11/xdm/xdm-config

DisplayManager._0.setup:        /etc/X11/xdm/arch-xdm/Xsetup
DisplayManager._0.startup:      /etc/X11/xdm/arch-xdm/Xstartup
DisplayManager._0.reset:        /etc/X11/xdm/arch-xdm/Xreset
DisplayManager._1.setup:        /etc/X11/xdm/arch-xdm/Xsetup
DisplayManager._1.startup:      /etc/X11/xdm/arch-xdm/Xstartup
DisplayManager._1.reset:        /etc/X11/xdm/arch-xdm/Xreset

对于 LightDM

LightDM 具有自动多座位检测功能(从 loginctl list-seats 提供的座位列表中提取)。如果您有一个手动 Xorg 配置文件并想使用它,请确保在那里指定了有效的 MatchSeat 值(参见上文)。这是因为 LightDM 会自动将 -seat seat0 或类似参数传递给 /usr/bin/X,因此 Xorg 将忽略任何 MatchSeat 不匹配当前座位的部分。(因此,如果您根本忘记指定 MatchSeat,这些部分将适用于每个座位,在显示设备的情况下,这意味着一个或多个座位很可能无法启动,因为它们都争夺同一显示器。)

如果您需要,可以在 /etc/lightdm/lightdm.conf 中进行配置。

[LightDM]
run-directory=/run/lightdm

[Seat:*]
greeter-session=lightdm-gtk-greeter
greeter-hide-users=false # Bug: lightdm-gtk-greeter does not load user saved session when greeter-hide-users=true[1]
session-wrapper=/etc/lightdm/Xsession

[Seat:seat0]
xserver-command=/usr/bin/X :0
# If you cannot put `MatchSeat "seat0"` in the `ServerLayout` section for some reason, you can force a layout here.
xserver-layout=seat0

[Seat:seat-1]
xserver-command=/usr/bin/X :1
xserver-layout=seat-1

对于自动登录多座位(无显示管理器)

编辑脚本 /boot/twin.sh

#!/bin/bash
cmd1="/bin/bash --login -c \"/usr/bin/xinit --"
cmd2="-nolisten tcp -keeptty -novtswitch -config xorg.multiseat.conf"
usr=(user1 user2)  # FIXME: assume user1, user2 is valid user id
declare -a pid
while true ; do
  for ((i=0; i<${#usr[*]}; i++)) ; do
    echo "usr[$i]=${usr[$i]} pid=${pid[$i]}"
    if [ -z "${pid[$i]}" ] || [ ! -d "/proc/${pid[$i]}" ] ; then
      # echo "pid ${pid[$i]} killed, execute again"  
      cmd3="-layout seat$i vt0"$((7+i))"\""
      if [ $i -gt 0 ] ; then
        cmd3="-sharevts $cmd3"
      fi
      #echo "cmd3=$cmd3"
      /bin/su ${usr[$i]} -l -c "$cmd1 :$i $cmd2 $cmd3" &
      pid[$i]=$!
      #echo "new pid=${pid[$i]}"
    fi
  done
  sleep 5  # check process exist per 5 second
done

打开 /etc/inittab 并按如下方式设置:

#id:3:initdefault:
id:5:initdefault:
...
x2:5:once:/root/twin.sh > /root/twin.log 2>&1

声音

每个座位一个声卡

一旦您将声卡 附加 到座位,PulseAudio 就会检测并使用它。

单声卡多用户:PulseAudio

如果两个用户想同时使用声卡,则必须使用声音服务器,PulseAudio 是最常见的。通常,PulseAudio 服务器只为活动用户运行,并且不允许多个用户实例。解决此问题的方法是使用系统范围的 PulseAudio 服务器。虽然这种方法作者不推荐,但它可能是最适用的设置。

为多用户配置,不使用系统模式守护进程

这将导致所有混音都传输到单个服务器。

将默认配置复制到主用户的主目录

$ cp /etc/pulse/default.pa ~/.pulse/

或者

$ cp /etc/pulse/default.pa ~/.config/pulse/

编辑文件,在末尾添加

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1

重新启动 PulseAudio,如果已在运行

$ pulseaudio -k
$ pulseaudio --daemonize=no

以用户身份重复此过程,为每个次要用户执行此操作

$ echo "default-server = 127.0.0.1" > ~/.pulse/client.conf
为系统范围的 PulseAudio 配置
  • 创建用户 pulse 并将其放入 audio 组(PulseAudio 会放弃 root 权限并切换到用户 pulse。组成员身份允许设备访问。)
  • 创建 pulse-access 组并将本地播放声音的用户放入其中(组成员身份用于对 PA 守护进程的本地访问进行访问控制。)
  • 在 /etc/pulse/default.pa 中明确声明访问权限
load-module module-native-protocol-unix auth-group=pulse-access 
auth-group-enable=1

创建 /etc/dbus-1/system.d/pulseaudio.conf 并包含以下内容:/etc/dbus-1/system.d/pulseaudio.conf

<?xml version="1.0" encoding="UTF-8"?>
<busconfig>
	<policy user="pulse">
		<allow own="org.pulseaudio.Server"/>
		<allow send_destination="org.pulseaudio.Server"/>
		<allow receive_sender="org.pulseaudio.Server"/>
	</policy>
</busconfig>

以 root 用户身份将 PA 作为系统范围启动

# pulseaudio --system

/var/run/pulse 应该会出现用于与守护进程通信的文件,即 pid 和 native。

用户访问

您可以作为非 root 用户检查与系统守护进程的通信,例如 pactl -s "unix:/var/run/pulse/native" list

可以在 /etc/pulse/client.conf 中启用对本地守护进程的自动网络连接。

auto-connect-localhost = yes

用户应该能够连接到 PA 服务器。系统范围守护进程的所有缺点实际上都变成了优点,例如能够控制其他用户流的音量(在 pavucontrol 中)。

故障排除

可以通过在 /etc/pulse/default.pa 中加载模块 load-module module-http-protocol-tcp 来启用 PA 的 http 接口进行调试,然后连接到 https://:4714/

单声卡多用户:ALSA

在移除 PulseAudio 的情况下进行设置,通过 alsamixer(1) equalizer 和软件混音共享音频。使用的相关硬件是 ATI Radeon HD 5850 和 Intel Sandy Bridge(板载)HD 3000。配置步骤可能会有所不同。

如果需要,可以根据具体硬件在 /etc/asound.conf 中进行配置,以便将音频同时分配给两个用户。另一个选项允许两个不同的用户通过各自的均衡器访问音频(稍后详述)。在使用 ALSA 并移除 PulseAudio 的情况下,声卡将在座位之间平均共享 - 为各种软件依赖关系应保留 libpulse。

接下来,删除相应的 ~/.asoundrc 文件(如果您删除了 PulseAudio,也删除相关的 PulseAudio 配置文件),然后为声音按照此模板配置 /etc/asound.conf

defaults.pcm.rate_converter "samplerate_best"

ctl.equal {
 type equal;
}

pcm.plugequal {
  type equal;
  # Modify the line below if you do not
  # want to use sound card 0.
  #slave.pcm "plughw:0,0";
  #by default we want to play from more sources at time:
  slave.pcm "plug:dmix";
}
#pcm.equal {
  # If you do not want the equalizer to be your
  # default soundcard comment the following
  # line and uncomment the above line. (You can
  # choose it as the output device by addressing
  # it with specific apps,eg mpg123 -a equal 06.Back_In_Black.mp3)
pcm.!default {
  type plug;
  slave.pcm plugequal;
}

只有最后登录的用户才拥有音频控制和访问权限,但如果您希望在不同用户之间平均共享音频,请将每个用户添加到 audio 组。

示例

usermod -a -G ftp joeblow
usermod -a -G ftp jillschmill

然后将此内容放入每个用户的各自的 ~/.asoundrc 中,而不是使用 /etc/asound.conf(此选项还包含各种调整以提高音频质量)。

defaults.pcm.rate_converter "samplerate_best"

ctl.equal {
 type equal;
}

pcm.ossmix {
    type dmix
    ipc_key 1024 # must be unique!
    ipc_key_add_uid false   # let multiple users share
    ipc_perm 0666           # IPC permissions for multi-user sharing (octal, default 0600)
    slave {
        pcm "hw:0,0"      # you cannot use a "plug" device here, darn.
        period_time 0
        period_size 1024 # must be power of 2.
        buffer_size 8192  # ditto.
        rate 44100
       #format "S32_LE"
       #periods 128 # dito.
       #rate 8000 # with rate 8000 you *will* hear,
       # if ossmix is used :)
    }
    # bindings are cool. This says, that only the first
    # two channels are to be used by dmix, which is
    # enough for (most) oss apps and also lets 
    # multichannel chips work much faster:
    bindings {
        0 0 # from 0 => to 0
        1 1 # from 1 => to 1
    }
}

pcm.plugequal {
  type equal;
  # Modify the line below if you do not
  # want to use sound card 0.
  #slave.pcm "plughw:0,0";
  #by default we want to play from more sources at time:
  slave.pcm "plug:ossmix";
}

#pcm.equal {
  # If you do not want the equalizer to be your
  # default soundcard comment the following
  # line and uncomment the above line. (You can
  # choose it as the output device by addressing
  # it with specific apps,eg mpg123 -a equal 06.Back_In_Black.mp3)
pcm.!default {
  type plug;
  slave.pcm plugequal;
}

可以通过以下方式访问均衡器:

alsaequal -D equal

每个用户都有一个可以单独配置的均衡器。

确保降低和静音您不使用的音频通道,关闭麦克风自动静音,并确保没有通道的增益高于 0,以避免 ALSA 音频错误。这可以通过 alsamixer 完成。

故障排除

Xorg 无法启动

查看 /var/log/Xorg.*.log 中的日志文件。每个座位都会有一个。阅读日志文件将显示座位试图使用的设备,您可能会看到类似两个座位试图使用同一显示设备的情况,因为您没有将其正确分配给特定的座位。

如果您使用的是显示管理器,请找出其日志文件所在位置,以便您可以检查它是否正确启动 Xorg 服务器,并且是否传递了必需的 -seat 参数。

我的 Windows 键不再工作

将此内容放入 启动文件 中。

xmodmap -e "add Mod4 = Super_L Super_R"

不稳定行为(黑屏无光标)

如果一切设置似乎都正确,但出于某种原因,您总是得到一个黑屏而没有光标,请尝试将 BIOS 中初始化的第一张卡设置为 PCI 卡。

桌面上的小黑框/点

这实际上是虚拟终端的一部分被绘制到 X 之上。它似乎是由 Linux 内核帧缓冲引起的。可以通过禁用帧缓冲或从主座位的 X 参数中删除 "-sharevts" 选项来解决此问题。

多媒体键无法工作

如果您的键盘有额外的“多媒体”键,您可能会发现它们在多座位设置中停止工作。这是因为这类键盘通常被表示为多个“事件”设备。正如您上面所做的那样,在此次使用 cat 命令读取每个 /dev/input/event* 设备,同时按下多媒体键。一旦找到正确的事件设备,为其添加一个单独的键盘 InputDevice 部分,然后使用 "SendCoreEvents" 选项将该 InputDevice 部分添加到相应的 ServerLayout 部分,该选项表示即使此设备不是核心键盘,也应处理来自此设备的输入。最终,您应该拥有类似以下内容的部分:

Section "InputDevice"
    Identifier      "Keyboard0"
    Driver          "evdev"
    Option          "Device" "/dev/input/event6"
    Option          "XkbModel" "evdev"
EndSection

Section "InputDevice"
    Identifier      "Keyboard0Multimedia"
    Driver          "evdev"
    Option          "Device" "/dev/input/event7"
    Option          "XkbModel" "evdev"
EndSection

Section "ServerLayout"
    Identifier     "Layout0"
    Screen      0  "Screen0" 0 0
    InputDevice    "Keyboard0" "CoreKeyboard"
    InputDevice    "Keyboard0Multimedia" "SendCoreEvents"
    InputDevice    "Mouse0" "CorePointer"
    Option         "AutoAddDevices" "no"
EndSection

Ctrl-Alt-Fx、Alt-Fx 键与虚拟终端冲突

(2010 年 10 月)我遵循了本指南,一切正常,除了 Alt-F1、Alt-F2... 会弄乱。然后我遵循了本指南 https://help.ubuntu.com/community/MultiseatX(阅读 Ubuntu 10.04 的部分)。

# cd /usr/bin
# ln -s X X0
# ln -s X X1

然后在 /usr/share/config/kdm/kdmrc 中按如下方式修复:

[General]
ConsoleTTYs=tty1,tty2,tty3,tty4,tty5,tty6
ServerVTs=7,8
StaticServers=:0,:1
ReserveServers=:2,:3
...

[X-:0-Core]
ServerVT=8
ServerCmd=/usr/bin/X1
ServerArgsLocal=-nolisten tcp -sharevts -novtswitch -keeptty -layout Seat1 -isolateDevice PCI:1:0:0

[X-:1-Core]
ServerVT=7
ServerCmd=/usr/bin/X0
ServerArgsLocal=-nolisten tcp -novtswitch -keeptty -layout Seat0 -isolateDevice PCI:0:2:0
...

它在我电脑上工作:一块板载 Intel 卡(xf86-video-intel 驱动程序),和一块 Nvidia 卡(xf86-video-nouveau 驱动程序)。您可以检查参数是否正确传递,方法是:

$ pgrep -af PCI
root     16993  1.6  1.3  32900 26772 ?        S    08:09   0:19 /usr/bin/X0 :1 vt7 -nolisten tcp -novtswitch -keeptty -layout Seat0 -isolateDevice PCI:0:2:0 -auth /var/run/xauth/A:1-ES6CCb
root     17124  5.9  0.5  18996 11980 ?        S    08:09   1:09 /usr/bin/X1 :0 vt8 -nolisten tcp -sharevts -novtswitch -keeptty -layout Seat1 -isolateDevice PCI:1:0:0 -auth /var/run/xauth/A:0-Wgiyza

ServerVT=7ServerVT=8 将被传递为 vt7vt8

使用 fbcon 内核参数修复 VT 行为

fbcon=map:n 传递给 内核命令行。(数字可能不同,请参阅 内核文档)。

上述值会导致 `[Ctrl]+Alt+FX` 切换到视频卡编号 n,其他视频卡只显示 Xorg。

参见

  • Multi-pointer X 解释了如何在同一会话中设置两个独立的设备对。