使用HTTP的实时音频流-选择协议和Java实现

使用HTTP的实时音频流-选择协议和Java实现,java,http,audio-streaming,internet-radio,Java,Http,Audio Streaming,Internet Radio,我正在尝试实现用于实时音频的简单HTTP服务器(Java)。假设有一个网站,你可以看到一个列表的歌曲正在播放一个接一个。当客户端连接到服务器-让我们在歌曲的中间-我想使用“范围”HTTP头,并发送从歌曲的那部分开始的数据范围。但是,如果在下载过程中连接暂时丢失(并且歌曲已完成)-服务器是否应该发送上一首歌曲并完成它-或者服务器是否应该发送正在播放的歌曲的那些部分?什么是最佳实践/原则? PS-我不是为音频流第三方软件寻找。 编辑: 现在,在对可用的实时流媒体技术进行了一些研究之后, 我看到了

我正在尝试实现用于实时音频的简单HTTP服务器(Java)。假设有一个网站,你可以看到一个列表的歌曲正在播放一个接一个。当客户端连接到服务器-让我们在歌曲的中间-我想使用“范围”HTTP头,并发送从歌曲的那部分开始的数据范围。但是,如果在下载过程中连接暂时丢失(并且歌曲已完成)-服务器是否应该发送上一首歌曲并完成它-或者服务器是否应该发送正在播放的歌曲的那些部分?什么是最佳实践/原则?

PS-我不是为音频流第三方软件寻找。

编辑:
现在,在对可用的实时流媒体技术进行了一些研究之后, 我看到了这些目标:
1.为简单的实时音频流选择协议

2.在Java(服务器端)中的协议实现

您不能随意剪切媒体并期望播放机能够播放它。这适用于裸MPEG流,但其他容器和编解码器可能会有问题。因此,除非客户端已经拥有部分文件,否则不要发送部分文件

你也有问题,当歌曲结束时,你要做什么,你就进入下一个

有两种方法可以实现这一点。其中之一就是让客户端可以使用静态媒体,然后在音频客户端中查找正确的时间

我会选择的方法是真正创建一个互联网广播流,每个人都在同一时间听到同一件事,因为您实际上有一个公共缓冲区,可以在同一时间从所有客户端复制数据块并将其发送给所有客户端。现在,如果您这样做,您需要使用支持任意拼接(MP3或AAC)的编解码器/容器,或者在将流发送到客户端时使用容器重新包装流。这是一个复杂的问题,所以最好使用现成的工具,比如Icecast。我知道你说你不是在寻找第三方解决方案,但这是最好的办法。如果您想自己完成这一切,您必须重新实现所有功能,或者只支持MPEG流

编辑:来自您的评论:

请您详细解释一下数据流格式,即[24576字节流][metablock][24576字节流][metablock]等。。如何分离块,元块的内容是什么

如果愿意,可以将SHOUTcast样式的元数据多路复用到流中。并非所有客户都支持这一点。如果他们这样做,他们将在请求中向您发送以下标题:

Icy-MetaData: 1
如果看到该标头和值,可以选择在流中包含元数据。元数据只是在每个流数据块之后注入。要包含元数据,首先需要确定流块的大小。距离太远,元数据将无法很好地与流对齐。距离太近,理论上是在浪费带宽(但不会太多,因为不变的元数据块只有一个字节长)。我通常坚持8KB。16KB有时甚至32KB的内存并不少见。在响应头中输出块大小(元数据间隔):

Icy-MetaInt: 8192
要开始工作,请向客户端发送8192字节(8KB)的音频流数据

现在是创建元数据块的时候了。以字符串开头,如下所示:

StreamTitle='This is my stream title';StreamUrl='';
您可以传入StreamUrl甚至其他字段,但现在只有StreamTitle真正被客户端使用。(
StreamUrl
过去可以通过大写字母或其他方式弹出浏览器,我不记得触发器是什么了。它不再使用了。)然后将此字符串转换为缓冲区,并用空字节(
0x00
)填充到最近的16个等分块。也就是说,如果元数据块的字符串版本为51字节长,则需要64字节长,以便添加13字节的
NUL
填充

关于字符集的快速注释。许多客户端在其元数据中支持UTF-8。有些没有。此外,如果必须在元数据中使用撇号
,则需要对其进行转义。不幸的是,似乎没有一个真正标准的方法来做到这一点。反斜杠有时有用。重复这个角色有时有效。不同的玩家工作方式不同。使用Winamp进行实验,看看它喜欢什么,因为这将是尽可能“正式”的。其他一切都可能只是一个坏客户。(如果您想变得非常狡猾,可以从
用户代理
请求头确定客户端,并相应地调整转义。)

现在您有了元数据块,只需在它的前面添加一个字节,以指示它的长度,除以
16
。因此,如果我们现在有一个64字节的元数据,我们将在其前面添加字节
0x04
,这表明我们的元数据是64字节长的。这总共提供了一个65字节的元数据块,我们现在将其发送到客户端。发送它


从这里开始,我们再次进入循环,在插入元数据之前再发送8KB的流数据。不过这次由于我们不想更改元数据,所以只发送
0x00
作为元数据块。同样,由于第一个字节指示块的长度,并且我们不更新标题,所以告诉客户机长度是
0
。我们仅在某些内容发生更改时发送字符串。

请回答问题或显示重复链接(如果存在),但如果您不知道答案,请不要关闭该链接。非常感谢您的解释。我也找到了你的答案。请您详细解释一下数据流格式,即
[24576字节流][metablock][24576字节流][metablock]等。
。如何分离块,元块的内容是什么?有什么官方解释吗?我没有测试/实现