构建你自己的网络收音机接收器
只需按下一个按钮,即可收听世界各地的社区。
晚上回到家,我喜欢按下一个按钮就能收听世界的声音。我曾在许多不同的地方居住过——从新西兰的达尼丁到新墨西哥州的圣达菲——在每个城镇,我都爱上了一个电台(通常是社区电台),它体现了当地的精神。只需按下一个按钮,我就可以重新与这些地方同步,并通过网络收音机访问新的社区。
为什么要构建你自己的网络收音机接收器?当然,一种选择是简单地使用接收器应用程序。然而,我发现最常见的应用程序并没有专注于手头的任务,而且越来越容易被提供额外的社交网络服务分散注意力。而且,我只想现在就听。我不想查看我的电脑或手机,再次登录,并忍受回忆 YAPW(又一个密码)的压力。我还发现,目前提供的网络收音机盒达不到我的期望。就像我说的,我住过很多地方——超过两个、四个或八个。我想要很多按钮,这样我只需一个手势就可以收听电台。最后,我注意到,如果我不直接访问源头,流媒体会变得越来越有问题。通常,通过“中间人”选择的流媒体会以广告或简介作为前言开始。或者有时“中间人”可能会把我绑定到音质低于最佳水平的流媒体。
因此,我转向构建自己的网络收音机接收器——一个有很多按钮的接收器,它允许我“收听”而又不会太霸道。在本文中,我分享我的经验。原则上,这应该很容易——你只需要一个 Linux 发行版、一艘航行的船和一个用于舵的外接键盘。实际上,这并不太难,但在航行过程中有一些障碍,我希望帮助你克服。
我的配料清单包括以下内容
- 一台带有超低电压(酷睿 2 双核)处理器的二手笔记本电脑。
- 一个带有光纤 TOSLINK 的音频接口。
- pyradio:一个开源的 Python 收音机程序。
- 一个外接键盘。

图 1. 我的硬件设置
为什么是笔记本电脑而不是树莓派或类似的船?主要是因为时间——特别是我的时间。花大约 50 美元找到一台大约十年的高质量笔记本电脑并不难,所以成本实际上并没有那么大的差别,而且我发现开发平台要快得多。
特别是,我使用了 ThinkWiki 网站来研究 Thinkpad 的 Linux 支持。在 eBay 上,我发现最便宜的设备通常在没有 HDD 的情况下出售——这对我来说很好,因为我想要一个小的 SSD 来保持电脑(其主要任务是音频)的安静。我最终选择了 Thinkpad X61,但那个时代的任何笔记本电脑都具有足够的性能,通常比任何低成本的单板计算机选项都要多得多。
我想要一个光纤音频链路,一个 TOSLINK,同样,ThinkWiki 是一个查找驱动程序支持等问题的极佳资源。我选择了一张二手的 Soundblaster Audigy Cardbus 声卡(因为该系统也兼作我的 FLAC 录音的音频服务器),这有点贵,但为了省钱,你可以在 eBay 上以大约 10 美元的价格购买一个 USB 转 TOSLINK 转换器。我喜欢 TOSLINK 是因为它固有的电气隔离,可以最大限度地减少来自接地环路的任何音频嗡嗡声。而且,我只是觉得通过光通信很酷。
另一个重要的硬件是键盘。为了进行原型设计,我只是抓取了一个带有 22 个键的无线数字键盘,但对于最终项目,我花了一点钱购买了一个专用的 48 键键盘(图 2)。当然,无线键盘的优势在于它可以充当遥控器,当切换电台时,我可以随身携带在房间里。

图 2. 专用 48 键键盘
将所有部件组装好后,下一步是安装你最喜欢的发行版。我选择了 Linux Mint,但我可能会为下一个迭代尝试 elementary。
主要的代码是 pyradio,它是一个基于 Python 的网络收音机调谐器。使用 snap 安装很简单
$ sudo apt install snapd
$ sudo snap install pyradio
我总是需要查找东西被放在哪里,为此我使用
$ cd /
$ sudo find . -name pyradio
在这种情况下,我找到了可执行文件 /snap/bin/pyradio。
像 Music on Console (MOC) 一样,pyradio 是一个基于 curses 的播放器。我发现自己最近又回到了 curses 界面,原因有几个:怀旧、编程的简洁性,以及试图摆脱曾经承诺成为通用门户但后来却陷入推送“服务”(即广告)的日益拥堵的浏览器控制界面。
如果你以前没有做过任何 curses 编程,请查看 Jim Hall 最近在 Linux Journal 中提供的 使用 ncurses 库的示例。如果你遇到任何安装问题,也可以查看 pyradio GitHub 存储库。你也可以在使用以下命令克隆存储库后从源代码构建 pyradio
$ python setup.py build
$ python setup.py install
你真的不需要了解太多 Python 知识,甚至不需要任何 Python 知识,就可以通过上面的两个简单命令从源代码运行。此外,根据你的设置,你可能需要在上面的命令中使用 sudo
。
如果一切顺利,并在将 /snap/bin 添加到你的路径后,发出命令
$ pyradio
将弹出一个屏幕,如图 3 所示。

图 3. pyradio 屏幕截图
你可以使用一些基于键盘的命令来驱动 pyradio,如下所示
- 上/下/j/k/PgUp/PgDown — 更改电台选择。
- g — 跳转到第一个电台。
- <n>G — 跳转到第 n 个/最后一个电台。
- Enter/右/l — 播放选定的电台。
- r — 选择并播放一个随机电台。
- 空格/左/h — 停止/开始播放选定的电台。
- -/+ 或 ,/. — 更改音量。
- m — 静音。
- v — 保存音量(不适用于 vlc)。
- o s R — 打开/保存/重新加载播放列表。
- DEL,x — 删除选定的电台。
- ? — 显示按键帮助。
- Esc/q — 退出。
在你进行键盘映射后,其中一些命令将会更改。
接下来,你将想要将你自己的电台列表添加到组合中。为此,我使用命令搜索文件 stations.csv
$ sudo find . -name stations.csv
并看到 snap 将文件放在
$ /home/[user_id]/snap/pyradio/145/.config/pyradio/stations.csv
使用编辑器打开 stations.csv,并将那里的默认电台替换为你自己的选择。例如,我的一些条目看起来像这样
KMUZ, http://70.38.12.44:8010/
KVMR, http://live.kvmr.org:8000/aac96.m3u
RNZ1, http://radionz-ice.streamguys.com:80/national.mp3 etc ...
语法和它看起来一样简单。字段分隔符是逗号,第一个字段是你想要的任何文本,大概是描述电台。我只使用呼号。第二个字段是流媒体的链接。这就是你面临的第一个障碍。找到你想要的所有流媒体可能有点乏味,特别是如果你想直接访问源头而不是来自聚合网站的辅助链接。此外,曾经只有少数几种编码格式(还记得 .ram 吗?),但现在有多种格式和专有服务。因此,识别流媒体的良好 URL 可能有点挑战。
我首先直接访问电台的网站,如果你幸运的话,它会提供给定流媒体的 URL。如果没有,你需要做一些搜索。使用 Google Chrome 浏览器,拉起页面 查看→开发者→开发者工具。屏幕的左侧是网页,右侧是几个用于开发者的窗口。单击标记为“网络”的菜单,然后启动音频流。在“网络”窗口下,逐步浏览标记为“名称”的列。你应该在右侧看到“请求 URL”出现,并且你想注意任何可能指向音频流的链接。它将是数据包来回弹跳很多的那个。复制 URL(以及“请求 IP”处的 IP 号),然后通过将 URL 或 IP:端口号粘贴到浏览器中的地址框中来测试它。URL 可能会导致音频流开始,或者它可能会指向一个包含信息的文件——例如播放列表文件(.pls 文件)——用于识别流。
对于一个具体的例子,考虑 KMUZ(俄勒冈州特纳的一个社区电台)。我首先访问 KMUZ 的主页,网址为 KMUZ.org。我注意到主页上的“在线收听”按钮,但在运行流媒体之前,我打开“开发者工具”中的“网络”窗口。当该窗口打开时,我单击“在线收听”按钮,并在请求的 URL 中的名称中搜索,看到 http://sc7.shoutcaststreaming.us:8010/,IP 号和端口为 70.38.12.44:8010。
将这些标识符中的任何一个粘贴到浏览器的 URL 框中,我发现流媒体来自(专有服务)Shoutcast,它提供了一个播放列表文件(.pls)。然后我使用编辑器打开播放列表文件(.pls 是 ascii 文件)以确认 IP/端口是用于收听 KMUZ 的流媒体。
请注意两点。首先,有很多格式/协议用于创建流媒体。你可能会在搜索过程中找到一个 MP3 (.mp3) 文件、一个多媒体播放列表文件 (.m3u)、一个高级音频编码 (.aac) 或只是一个普通的 URL。因此,获得你想要的流媒体的链接需要一些搜索和尝试。其次,如果流媒体有前言,你通常可以通过等待流媒体传递到直播节目来避免这种情况,然后抓住直播流。这样,下次你启动电台时就不需要收听前言了。你选择的音频播放器(VLC、MPlayer 或类似)需要能够解码你最终获得的那组特定电台的任何格式。
你可能遇到的另一个困难是映射键盘上的按键。当然,这取决于你使用的特定键盘。如果你幸运的话,键盘是有文档记录的。如果没有,或者要仔细检查映射,请使用程序在你按下每个键时捕获键码。这是一个用于查找键码的 Python 程序
from msvcrt import getch
while True:
print(ord(getch()))
你需要做的另一个小段代码是将每个按键指向一个电台。找到 stations.csv 所在的目录中的 radio.py 程序。编辑 Python 脚本,使每个按键都导致所需的动作。例如,station.csv 中的流媒体由 pyradio 从 1 到 N 索引。如果列表中的第一个电台是 KMUZ,并且你想使用的键的键码是“h”,那么添加或修改 radio.py 脚本以包含代码片段
if char == ord('h'):
self.setStation(1)
self.playSelection()
self.refreshBody()
self.setupAndDrawScreen()
你将使用的函数/方法被清楚地标记,例如上面的 playSelection
方法。因此,你真的不需要任何 Python 的详细知识就可以进行这些更改。但请确保任何更改都不会与脚本中键码的其他分配冲突。诸如“静音”之类的函数可以使用代码片段重新分配
if char == ord('m'):
self.player.mute()
return
无论你进行什么更改,都要尽量保持程序可以从笔记本电脑键盘使用,这样你仍然可以在没有外接键盘的情况下进行基本操作。
差不多就是这样了。然而,每个好的程序都应该有一个小技巧,以免冒犯神灵。我希望 pyradio 程序在启动后自动运行,为此,我在机器中放置了一个幽灵。有更自然的方法可以在启动时运行 pyradio,但我喜欢一种相当怪异的方法,即在登录时使用带有 xdotool
的 shell 脚本
sleep 0.2
xdotool mousemove 100 100 click 1
xdotool type "pyradio"
xdotool key KP_Enter
xdotool
允许你编写键盘和鼠标输入脚本,使其像你实际从键盘输入一样运行。它在 curses
程序中非常方便。
最后,如果我不推荐一个好的广播节目,那我就失职了。我目前最喜欢的是新西兰国家广播电台的 Matinee Idle,它在假期期间每年播放几次。它就像是为 50 岁以上的人准备的大学广播。
资源