您不能随意剪切媒体并期望播放器能够播放它。这适用于裸 MPEG 流,但其他容器和编解码器可能会遇到问题。因此,除非客户端已经拥有其余部分,否则不要发送部分文件。
当歌曲结束并进入下一首时,您还存在如何做的问题。
有两种方法可以实现这一点。其中之一是让您的客户可以使用静态媒体,然后在音频客户端寻找正确的时间。
我会选择的方式是真正创建一个互联网广播流,每个人都可以同时听到相同的内容,因为您实际上有一个公共缓冲区,可以在同一时间从其中复制块并将其发送到所有客户端。现在,如果您这样做,您将需要使用支持任意拼接(MP3 或 AAC)的编解码器/容器,或者在将流发送到客户端时使用容器重新包装流。这是一个复杂的问题,所以最好使用现成的东西,比如 Icecast。我知道您说您不是在寻找第三方解决方案,但这是最好的方法。如果您想自己完成这一切,则必须重新实现所有这些,或者仅支持 MPEG 流。
编辑:来自您的评论:
您能否详细解释一下数据流格式,即[24,576 bytes of stream] [metablock] [24,576 bytes of stream] [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,看看它喜欢什么,因为那将是你能得到的“官方”。其他一切可能只是一个坏掉的客户。 (如果你想变得非常狡猾,你可以从User-Agent请求头中确定客户端并相应地调整你的转义。)
现在您有了元数据块,您只需在它的前面添加一个字节,表示它的长度,除以16。因此,如果我们现在有一个 64 字节的元数据,我们将在它的前面添加字节 0x04,这表明我们的元数据是 64 字节长。这总共提供了一个 65 字节的元数据块,我们现在将其发送给客户端。发送。
从这里,我们再次进入循环,在插入元数据之前再发送 8KB 的流数据。这一次,由于我们不想更改元数据,我们只发送0x00 作为我们的元数据块。同样,由于第一个字节表示块的长度,并且我们没有更新标题,所以告诉客户端长度是0。我们只在发生变化时发送字符串。