Closed cosven closed 1 year ago
Nowplaying 功能在 Linux 系统上可以比较容易实现。Linux 的进程间大都通过 dbus 来进行通信,FeelUOwn 可以通过它将当前播放的信息传输给系统,并且系统可以通过这个通信来控制音乐播放器。通信接口是 mpris2。
而 macOS 上没有统一的进程间通信方式,并且系统也没有给 nowplaying 定义 RPC 接口。但官方有提供一些 swift/objc 的一些代码示例。因此,在 macOS 上实现 nowplaying 功能有两种可行的方式:
fuo RPC server <--- client ---> MPNowPlayingInfoCenter
考虑到性能、可调试性和 native app 带来的更多可能性,我倾向选择第 2 种方案。
方案 2 要实现,关键是实现这个 client。而 client 有几个关键问题
问题 1 目前已经攻克,主要难点在于看懂 macOS 文档,以及编写一个 swift 程序。
对于问题 2,则需要 FeelUOwn 有一个能够通过 RPC 向外 push 信息的方式。dbus + mpris2 本质就是一种 push 的方式。pull 方式不适用于这个场景,因为播放器的进度等信息都是实时的,而使用 push,能极大的较少 poll 带来的性能开销,因为 push 只需要在进度发生突变的时候进行通知即可。FeelUOwn 现有的 pubsub 功能是实现 push 较好的方式。
调研了解到有这些技术可以实现 pubsub 实现,有
2,3,4 要么依赖太重,要么不跨平台。1 是一个不错的侯选项。就像 RPC 一样,之前也有考虑基于 HTTP 协议的 RPC,比如 JSONRPC 等。使用这些技术的主要好处是不需要自己造轮子,坏处有两个:json 可读性不强;http 偏重。
当前,FeelUOwn 有一个 pubsub 的实现,但它比较简单:一个 TCP 连接只能 pub 一个 topic,并且传输的是字节流,没有消息的概念。这让 sub 端能做的事情比较有限,需要支持:在一个连接中订阅多个 topic。
客户端发送
use version 2.0 sub player.*,app.*
客户端应该收到
OK pubsub 1.0 ACK ok {length} // 注:这个是 use version 2.0 的 response {body} ACK ok {length} // 注:这个是 sub player.*,app.* 的 response {body} 消息1 消息2
和 fuo RPC 响应的结构相似,这里的消息也分为两部分:报头(header)和正文(body)。报头是一行,以 \r\n 结束。报头里面会包含正文的大小等信息。
\r\n
MSG {topic_name} {body_length} #: json [0, null]
之后可能在报头添加更多字段,比如添加正文格式:
MSG {topic_name} {body_length} {body_type} MSG {topic_name} {body_length} #: {body_type}
为了保证向前兼容,客户端解析正文长度的时候应该使用类似如下代码
header = parse_header() body_length = header.split(' ')[2]
RPC 与 pubsub 的解析可以编写一个 Python SDK。其它 swift 可以参考规范或者 Python SDK 的代码来实现。
nowplaying 已经在 #674 中支持
简介与背景
Nowplaying 功能在 Linux 系统上可以比较容易实现。Linux 的进程间大都通过 dbus 来进行通信,FeelUOwn 可以通过它将当前播放的信息传输给系统,并且系统可以通过这个通信来控制音乐播放器。通信接口是 mpris2。
而 macOS 上没有统一的进程间通信方式,并且系统也没有给 nowplaying 定义 RPC 接口。但官方有提供一些 swift/objc 的一些代码示例。因此,在 macOS 上实现 nowplaying 功能有两种可行的方式:
考虑到性能、可调试性和 native app 带来的更多可能性,我倾向选择第 2 种方案。
方案概述
方案 2 要实现,关键是实现这个 client。而 client 有几个关键问题
问题 1 目前已经攻克,主要难点在于看懂 macOS 文档,以及编写一个 swift 程序。
对于问题 2,则需要 FeelUOwn 有一个能够通过 RPC 向外 push 信息的方式。dbus + mpris2 本质就是一种 push 的方式。pull 方式不适用于这个场景,因为播放器的进度等信息都是实时的,而使用 push,能极大的较少 poll 带来的性能开销,因为 push 只需要在进度发生突变的时候进行通知即可。FeelUOwn 现有的 pubsub 功能是实现 push 较好的方式。
pubsub 的方案选择
调研了解到有这些技术可以实现 pubsub 实现,有
2,3,4 要么依赖太重,要么不跨平台。1 是一个不错的侯选项。就像 RPC 一样,之前也有考虑基于 HTTP 协议的 RPC,比如 JSONRPC 等。使用这些技术的主要好处是不需要自己造轮子,坏处有两个:json 可读性不强;http 偏重。
当前,FeelUOwn 有一个 pubsub 的实现,但它比较简单:一个 TCP 连接只能 pub 一个 topic,并且传输的是字节流,没有消息的概念。这让 sub 端能做的事情比较有限,需要支持:在一个连接中订阅多个 topic。
pubsub 的细节
客户端发送
客户端应该收到
消息结构
和 fuo RPC 响应的结构相似,这里的消息也分为两部分:报头(header)和正文(body)。报头是一行,以
\r\n
结束。报头里面会包含正文的大小等信息。之后可能在报头添加更多字段,比如添加正文格式:
为了保证向前兼容,客户端解析正文长度的时候应该使用类似如下代码
其它
RPC 与 pubsub 的解析可以编写一个 Python SDK。其它 swift 可以参考规范或者 Python SDK 的代码来实现。