在 WSL 上运行网易云音乐客户端

为什么要在 WSL 上运行呢?因为今天在虚拟机里测试的时候偶然发现,云音乐的 Linux 客户端无视了大部分播放限制,比起 Windows 客户端要不知高到哪里去了。——这是一条新的路,不是俗套的本地代理。我一直是挂着代理用云音乐,但是毕竟代理有速度(勉强能接受)和隐私两个问题;还有一个无法下载封面的副作用。

发现了这个有意思的东西之后,我首先测试这是不是因为网络连接方式的不同导致的。如果两个客户端的内部逻辑是一样的,那么在不在虚拟机内应该不会影响可播放与否。除此之外就可能是客户端的逻辑不同了。不管是哪一种,都需要 WSL 来测试。WSL 和主机是共享端口和硬件的,所以不存在虚拟硬件,也不存在桥接,在服务器看来和其宿主是一样的。正好作为实验组。

为了验证猜想,同时也是解决代理带来的问题,我决定在 WSL 上运行云音乐客户端。

摸索试验花了五个小时(包括本文开始写作之后),大概有了一套理论,不过仍然有暗坑。使用注意。


首先,客户端在虚拟机(Ubuntu 17.10)里运行,一切正常。标称的最低支持是 Ubuntu 14.04。

开始进入 WSL。由于 WSL 不带图形界面,所以我们装一个。大体过程如这篇教程。不过注意 xfce4-terminal 要在 xfce4 之后安装,而且建议不要用那个下拉的终端模拟器(看个人,我是因为习惯从任何目录直接开终端,而那玩意儿不支持)。还有就是,和教程不同的,如果用的是较新的 WSL,那么 D-Bus 就不用修了

装完之后安装客户端。一运行,怎么什么反应都没有?开控制台,启动 netease-cloud-music,看输出。结果发现了异常的原因是这样一个错误(类似这个):

Assertion ‘pthread_mutex_unlock(&m->mutex) == 0’ failed at pulsecore/mutex-posix.c:108, function pa_mutex_unlock(). Aborting.

开始的时候我没注意看。客户端不是还依赖 VLC 嘛,所以我就打开了 VLC,结果同样无法启动,报告的是类似的错误。想了想应该是 PulseAudio 的问题。(以前在 WSL 上试过 ALSA 结果根本不能用……)找。顺着找到的东西继续翻,首先原因是这个,楼下有人提了简单的 workaround。不过我就没这个条件重新编译了,于是继续翻,果然有人做好了。于是添加 PPA 并重新安装 libpulse0(自然也要重新安装 xfcenetease-cloud-music)。

还有一些说明。不过里面的内容过时了。PulseAudio 的 Windows community port 版本才是1.1,太老了。自动安装脚本所安装的是版本6,也太老了——而且没法正常运行(路径问题)。

那怎么办呢?PulseAudio 的 FAQ 指出了一种方法,用 Cygwin 的组件。自然,作为一个合格的开发人员,Cygwin 肯定是有的。可以见到,此处的版本是11.1,比上面两个要新得多。安装之后,照着配置。稍微不同的是这里不使用 default-server 配置项,而是在 WSL 的 .bashrc 中加入:

1
export PULSE_SERVER=tcp:localhost

但是运行又出了问题,报告“failed to create secure directory”。解决方法也是有的。不过为什么不更自动化一点呢?在 Cygwin 的 .bashrc 中加入:

1
2
export PULSE_STATE_PATH=$HOME/.config/state
export PULSE_RUNTIME_PATH=$HOME/.config/runtime

这样就能正常运行 pulseaudio 这个服务端了。启动之后,在 VLC 和云音乐客户端就能听到声音了。

屏幕截图

不过可能你也注意到了,输出一直很糟糕。我们接着来解决播放的问题。

首先使用 -vvv 选项启动 pauseaudio。从输出中可以看到出现大量这样的消息:

D: [waveout] sink-input.c: Requesting rewind due to uncorking

D: [(null)] module-suspend-on-idle.c: Sink output becomes busy, resuming.

D: [waveout] protocol-native.c: Requesting rewind due to end of underrun. (※这一条会出现多次)

D: [waveout] sink-input.c: Requesting rewind due to corking

D: [(null)] module-suspend-on-idle.c: Sink output becomes idle, timeout in 5 seconds.

D: [waveout] protocol-native.c: Requesting rewind due to end of underrun.

会不会是 waveout 模块的锅呢?这个配置已经得到了修正。那只能猜想是 corking(自动降低音量)的问题了。我尝试取消加载 modue-role-cork,感觉上好一点了——至少只在开头的地方会出现噪音。搜索了一下之后我认为这应该是 VLC 播放对齐(aligning)的问题,比如这个讨论


在折腾的过程中,我发现云音乐客户端有很大概率无法正常启动,进程挂在那里,窗口不出现。虽然尝试解决了一下,但是仍然十分玄学。随着后面 PulseAudio 的调整,启动成功率似乎高一点了。

为了减少它的烦人程度,不用每次都手动终止进程(ps -ef | grep xxx 然后 kill yyy),建议安装 xfce4-taskmanager


对 PulseAudio 配置文件的修改:

default.pa 中——

在“Network access”节增加:

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

取消加载 module-role-cork 模块(我们也不需要):

1
#load-module module-role-cork

daemon.conf 中——

设置启动为守护进程:

1
deamonize = yes

注意,一旦成为了守护进程,就看不到输出,就无法调试了。不过好处是启动后即使关闭了 Cygwin Bash,pulseaudio 仍然在运行。

修改 exit-idle-time,配合守护进程(要不过一段时间就自动退出了):

1
exit-idle-time = -1

仍然有的问题:

  1. 8-bit 音乐,比如这种,无法输出,全是卡顿。从调试信息中可以见到 CEF 除了启动了标准的声音客户端,系统还分配了一个“尖峰检测”客户端。我猜是这个平滑波形的问题。
  2. 类似地,根据乐曲开头的规则程度,会有不同时长的垃圾信号。这个接近玄学。
  3. 会变调。频繁卡顿过后有一段时间音调比原曲要高一点(大约3度),然后过一段时间就降回来了。这可能还是采样的缓冲问题。

总之就要接受这样一个过程:

1
2
|-- t1 ->|-- t2 -->|-- t3 (~2s) -->|-- t4 -->|
| 卡顿 | 音调异常 | 降调 | 正常播放 |

还有一点奇怪的是,尽管云音乐用了 VLC 作为后端,但是 VLC 在进行转到指定时间(seek)结束的时候还会像开头那样来一段卡顿,严重的甚至会影响视频解码(怎么回事?),而云音乐不会。不知怎么解释。


好像禁止了 module-role-cork 还是会出问题……虽说这个模块是调整麦克风输入的(检测到输入较大,如讲话时,降低其他应用程序的音量),其实跟输出波形也应该么关系(不带反馈),但还是不知道怎么回事。同一首几分钟的歌,有时播放了几秒就稳定下来开始降调了,有时候播完了都是卡顿。唉,玄学。只能说 Linux 的(普通)用户体验还是太差太差了,不要说什么“hackable”,我不想投入,也没精力投入在这些根本不是目标、不值得操心的事情上。而 Linux 下的应用软件,就是能工作了算是走运,不能工作,假如找到了某种方案,必须附一句 YRMV。而且还真的就是 YRMV。心疼巴塞罗那的市政局工作人员

分享到 评论