当你的服务器没有麦克风时
بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ
我如何让 Claude Code 的语音模式在 SSH 上工作
我一直通过 SSH 在远程 Linux 服务器上运行 Claude Code。这是一个很棒的配置——服务器有更多资源,而且我可以从任何地方访问它。但当我尝试使用语音模式时,立刻遇到了问题:
cannot find card '0'麦克风不工作。以下是原因和我的解决方法。
问题
Claude Code 的语音模式需要麦克风。在你的本地机器上这很明显——你有声卡、麦克风和管理一切的音频守护进程。但我的远程服务器就是:一台服务器。没有声卡,没有麦克风,没有任何音频硬件。
当 Claude Code 尝试访问音频时,它会回退到 ALSA(Linux 的底层音频层),ALSA 会寻找物理设备。但没有。所以报错了。
为什么这个问题可以解决
Linux 的特点是:像 PipeWire 和 PulseAudio 这样的音频系统不依赖于硬件——它们是管理音频流的守护进程。而且它们「开箱即用」地支持网络透明性。这意味着你可以通过 SSH 干净、安全地将本地麦克风转发到远程机器。
解决方案
思路很简单:
- 让你的本地音频守护进程接受 TCP 连接
- 使用 SSH 的反向隧道功能将该端口转发到远程机器
- 让远程机器使用该隧道作为音频服务器
我们一步步来。
第一步:让本地音频服务器接受 TCP 连接
在你的本地机器上,将默认的 PipeWire PulseAudio 配置复制到你的用户目录:
cp /usr/share/pipewire/pipewire-pulse.conf ~/.config/pipewire/pipewire-pulse.conf然后打开 ~/.config/pipewire/pipewire-pulse.conf,找到 server.address 块,添加 TCP 地址:
server.address = [ "unix:native" "tcp:127.0.0.1:4713" # 仅 localhost——用于 SSH 音频转发]然后重启 PipeWire:
systemctl --user restart pipewire pipewire-pulse这告诉 PipeWire 在 TCP 端口 4713 上监听,但仅在 localhost 上——所以不会暴露给网络。因为写在配置文件中,重启后自动生效。
第二步:使用反向隧道 SSH
不要使用简单的 ssh user@server,添加 -R 标志:
ssh -R 4713:127.0.0.1:4713 user@your-server这告诉 SSH:「所有连接到远程机器 4713 端口的流量,都通过隧道转发回我本地机器的 4713 端口。」音频流量在加密的 SSH 连接内传输。
第三步:告诉远程机器音频服务器在哪里
登录远程机器后,设置这个环境变量:
export PULSE_SERVER="tcp:127.0.0.1:4713"现在任何使用 PulseAudio/PipeWire 的应用都会连接到这个端口——它直接通向你的本地麦克风。
第四步:修复 ALSA
一些应用(包括 Claude Code 的回退机制)直接使用 ALSA,而 ALSA 不知道 PULSE_SERVER。在远程机器上创建 ~/.asoundrc:
pcm.!default { type pulse }ctl.!default { type pulse }这告诉 ALSA:将所有音频通过 PulseAudio 路由,而不是寻找本地硬件。确保安装了必需的包:
sudo apt install libasound2-plugins pulseaudio-utils第五步:测试
仍在远程机器上,运行:
pactl info如果一切正常,你会看到你本地机器的音频服务器信息——包括你的麦克风作为默认源。这就是确认。
实际工作原理
在看它们如何连接之前,先分别理解每个部分会有帮助。
PipeWire 通常如何工作
在你的本地机器上,PipeWire 作为后台守护进程运行。它拥有你的物理麦克风和扬声器。应用不直接与硬件通信——它们通过 Unix 套接字(如 /run/user/1000/pulse/native 这样的文件)连接到 PipeWire,并说「给我音频」。PipeWire 处理硬件。
TCP 模块的作用
通常 PipeWire 只在本地 Unix 套接字上监听。通过在 PipeWire 配置中添加 "tcp:127.0.0.1:4713",你告诉它:也在 localhost 的 TCP 端口上监听。现在它通过网络接受相同的音频请求,而不仅仅是通过本地套接字。
SSH 隧道的作用
SSH 有一个叫做反向端口转发(-R)的功能。当你这样连接:
ssh -R 4713:127.0.0.1:4713 your-serverSSH 告诉远程机器:「所有连接到你的 4713 端口的流量,通过这个 SSH 连接转发到我的 4713 端口。」
所以隧道看起来像这样:
%%{init: {"flowchart": {"useMaxWidth": false}} }%%
graph LR
A["remote:4713"] ==> B["SSH 隧道"] ==> C["localhost:4713(你的 PipeWire)"] PULSE_SERVER 的作用
在远程机器上,PULSE_SERVER=tcp:127.0.0.1:4713 告诉所有音频应用:「不要寻找本地音频守护进程——连接到这个 TCP 地址。」
全景图
所有部分组合在一起,音频路径看起来像这样:
%%{init: {"flowchart": {"useMaxWidth": false}} }%%
graph TD
A["Claude Code(远程)"] --> B["远程的 tcp:127.0.0.1:4713"]
B --> C["SSH 反向隧道"]
C --> D["你本地的 PipeWire,端口 4713"]
D --> E["你的物理麦克风"] 你的声音从硬件到 PipeWire 到 TCP 套接字到 SSH 隧道到远程服务器到 Claude Code。远程机器永远不需要自己的音频硬件。
.asoundrc 的作用
一些应用完全绕过 PulseAudio/PipeWire,直接与 ALSA 通信——Linux 更底层的音频层。ALSA 不知道 PULSE_SERVER。~/.asoundrc 文件通过告诉 ALSA 来修复这个问题:「当有人请求默认音频设备时,通过 PulseAudio 路由,而不是寻找硬件。」所以即使基于 ALSA 的应用也最终通过同一个隧道。
永久配置
上面的配置适用于一次会话。要永久配置:
在远程机器上 —— PULSE_SERVER 应该在 ~/.zshrc(或 ~/.bashrc)中:
echo "export PULSE_SERVER='tcp:127.0.0.1:4713'" >> ~/.zshrc对于 SSH —— 在本地机器的 ~/.ssh/config 中添加 RemoteForward,这样你不用每次都输入 -R 标志:
Host your-server HostName your-server-ip User your-user RemoteForward 4713 127.0.0.1:4713现在简单的 ssh your-server 就会自动建立隧道。
对于本地 TCP 模块 —— 已在第一步完成。端口 4713 在每次登录时自动打开。
总结
| 内容 | 位置 | 命令 |
|---|---|---|
| TCP 模块(永久) | 本地(~/.config/pipewire/pipewire-pulse.conf) | 将 "tcp:127.0.0.1:4713" 添加到 server.address |
| SSH 隧道(永久) | 本地(~/.ssh/config) | 在 Host your-server 下添加 RemoteForward 4713 127.0.0.1:4713 |
| 设置音频服务器 | 远程(~/.zshrc) | export PULSE_SERVER='tcp:127.0.0.1:4713' |
| 修复 ALSA | 远程(~/.asoundrc) | pcm.!default { type pulse } |
| 安装插件 | 远程 | sudo apt install libasound2-plugins pulseaudio-utils |
五个步骤,无需第三方工具,无需复杂配置。Linux 做它擅长的事。
航空航天工程师
公开透明的道德创业者
你专注你的事业
我负责数字化的部分