解决Linux版网易云音乐无法播放无损格式(Flac)音乐的问题

前言

之前, 我基本都在PC上听音乐, 日常的需求基本可以满足了. 要听HiFi?自己抓CD或逛逛各分享站, 再用PC或手机OTG接个DAC加声放. 所以网易云音乐会员也没怎么开.

之后,为了舒适我日常的交通行程,购入了 Sony WH-1000XM2 蓝牙降噪耳机, 编码格式支持SBC,AAC,aptX,aptX HD,LDAC, 真是吓人; 而 Sony 也在 Android 8.0 开放了自己 ldac编码器 的代码, 厂商可以很容易的加入支持, 各知名ROM也直接将LDAC支持编译了进去; 我渐渐转向使用Android手机听音乐, 于是也开了网易音乐会员听无损(我知道有些是fake).

总之, 于是就发现了Linux版网易云音乐无法播放无损格式的问题. 在另一方面, 由于LDAC编码器开放了源代码, 并且aptX/aptX HD编码支持也在FFmpeg 4.0后加入其中, 在2018年4月的时候我就在构想能不能把LDAC编码的支持加入到Linux中?

在同年8月, 我终于将LDAC支持加入了pulseaudio的蓝牙模块中, 之后我陆续添加了aptX,aptX HD,AAC支持, 于是我又开始用PC+蓝牙LDAC听音乐了; 但网易云音乐Linux版无法播放无损的问题困扰了我几个月, 我自己也尝试摸索了一下, 但最后只发现问题与vlc播放flac有关.

分析

直到前几天我通过Google网易云音乐播放flac时的报错信息[00007f9b30003c50] prefetch stream error: unimplemented query (264) in control发现了下面的文章

https://blog.duama.top/2019/03/03/解决网易云音乐Linux版无法播放无损/

我也通过一番抓包并浏览VLC源码渐渐了解了原因; 原来, Linux版网易云音乐通过调用后端api获取音频文件URL, 然后就直接交给VLC了, VLC优先通过HTTP Header中的Content-Type获取文件类型(mime-type), 再根据mime-type选择demuxer; 问题就出在这里, 当音频为flac时, 上面提到的音频文件URL获取的HTTP Header中的Content-Typeaudio/mpeg, 这是给mp3用的, flac文件正确的mime-type应该是audio/flac; 重现一下网易云音乐播放无损音乐的流程, 网易云音乐获取FLAC音频文件URL->VLC通过Content-Type获取文件类型为audio/mpeg->VLC选择mpeg解码器解码flac文件->VLC解码失败->网易云音乐播放失败.

知道了原因, 我们就可以开始解决它了, 上面提到的文章说是用Privoxy更改Content-Type(HTTP劫持), 然后设置http_proxy环境变量; 但不知道为什么, 我通过这种方式并不能截取到音频文件URL的HTTP流; 此外, 我个人也不希望就为了一个桌面应用在后台始终运行Privoxy; 于是我尝试寻找其他解决方法.

解决方案

在vlc源代码modules目录下运行grep -r "Content-Type", 发现了VLC获取"Content-Type"的函数调用

access/http/resource.c:    const char *type = vlc_http_msg_get_header(res->response, "Content-Type");

进入代码, 发现上面res的结构体有一个path的变量, 那么问题就简单了, 只要判断res->path后缀为flac, 那么就把*type变量值改为"audio/flac"就行了; 我在gist上创建了PATCH和可用的PKGBUILD文件(VLC v3);或点击此获取PATCH;

这里有两个解决方法

  1. 应用PATCH后编译安装, 全局生效
  2. 应用PATCH编译后设置 LD_LIBRARY_PATH=<编译后VLC的lib目录>

应用PATCH, 编译

安装flac mpg123 libmpeg2 lua libmad libpulse alsa-libjack 的devel包及其他必要依赖, 下载vlc v3源码1和ncm.patch

$ cd vlc
$ patch -p1 < <到patch文件的路径>
patching file modules/access/http/resource.c
$ ./configure  \
      --prefix=/usr  \
      --disable-rpath \
      --enable-mpg123 \
      --enable-flac \
      --enable-libmpeg2 \
      --disable-avcodec \
      --disable-swscale \
      --disable-a52
...
$ make -j$(nproc)
# 安装到用户目录,不覆盖系统vlc
$ make DESTDIR=$HOME/.local/share/vlc-patching install

如果你不想编译的话,可以下载我的预编译包,适用用于当前Arch Linux, 其他Linux分布版可能会有库依赖缺失的问题

设置LD_LIBRARY_PATH运行网易云音乐

$ env LD_LIBRARY_PATH=$HOME/.local/share/vlc-patching/usr/lib netease-cloud-music

如果用的是我的预编译包, 上面命令中的$HOME/.local/share/vlc-patching/改成解压后的目录路径

也可以把网易云音乐desktop文件的Exec=netease-cloud-music %U如上更改

Comments

添加新评论