如何在 iOS 中播放来自服务器的流式 PCM 数据?

Posted

技术标签:

【中文标题】如何在 iOS 中播放来自服务器的流式 PCM 数据?【英文标题】:How to play streaming PCM data from server in iOS? 【发布时间】:2016-11-22 03:06:43 【问题描述】:

我正在尝试开发从服务器播放流式 PCM 数据的应用程序。

我用过AudioQueue,但是效果不好。

PCM 数据格式(来自服务器):

Sample rate = 48000, num of channel = 2, Bit per sample = 16

而且,服务器没有将固定字节流式传输到客户端。

(流式可变字节。例如:30848、128、2764、...字节)

我的源代码:

在这里,我设置的 ASBD 结构和创建音频队列对象 (语言:斯威夫特)

// Create ASBD structure & set properties.
var streamFormat = AudiostreamBasicDescription()

streamFormat.mSampleRate = 48000
streamFormat.mFormatID = kAudioFormatLinearPCM
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked
streamFormat.mFramesPerPacket = 1
streamFormat.mChannelsPerFrame = 2
streamFormat.mBitsPerChannel = 16

streamFormat.mBytesPerFrame = (streamFormat.mBitsPerChannel / 8) * streamFormat.mChannelsPerFrame
streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame
streamFormat.mReserved = 0

// Create AudioQueue for playing PCM streaming data.
var err = AudioQueueNewOutput(&streamFormat, self.queueCallbackProc, nil, nil, nil, 0, &aq)

...

我已经像上面一样设置了 ASBD 结构并创建了 AudioQueue 对象。

AudioQueue 可以很好地播放流式传输的 PCM 数据几秒钟,

但很快播放声音就会打开和关闭。我能做什么?

(仍在流式传输和排队 AudioQueue)

请给我任何想法。

【问题讨论】:

低带宽格式有效吗? 对不起?不知道你说的好不好。 当您尝试流式传输更紧凑的格式(如 mp3)时是否有效? 我只用它来播放 PCM 数据。要播放 mp3、AAC 等格式,请将 AudioQueue 与 AudioFileStream API 结合使用。 即 48000/s*4bytes*8bits/byte = 1.5Mbit。您的网络能否维持这种吞吐量? 【参考方案1】:

你需要做(至少)两件事:

您需要缓冲数据以处理来自服务器的数据与音频队列回调请求的数据之间的延迟抖动和不同的数据包大小。一个典型的解决方案是使用一个循环的 fifo/buffer,预先填充了一定数量的数据,足以处理最坏的情况下的网络抖动(你需要统计分析这个数字)。音频队列回调可以将请求的数据量从循环 fifo 中复制出来。网络代码试图保持填充。

当两个速率不够相同时,您可能还需要一些方法来隐藏错误:例如当网络速率太慢时复制或合成额外声音的某种方法,以及当网络速率太高时忽略样本的某种方法,这两种方法都试图尽可能地听不见,并且在任何速率下都不会产生响亮的咔哒声不连续或网络中断。

【讨论】:

第二部分仅适用于实时流。否则,客户端可以控制从服务器读取数据的速度并使其适应播放速度。 即使是非实时流也可能会出现短暂的网络中断(拥塞、丢失数据包过多等)。 我部分同意。如果您有缓冲(无论如何都是必需的),则只剩下长时间的瞬态网络丢失。您将无法用重复或合成的声音填充它们。但我同意需要以某种方式避免大声点击。 感谢您的回答 :) 。我试过你的方法,使用循环缓冲区。在这一点上,声音播放感觉比以前好多了。 (不完全修复它。)我猜,如何播放像 android 的 AudioTrack 类的声音? 很好的答案@hotpaw2 - 你有更多细节,或者甚至是伪代码实现吗?特别是循环缓冲区+动态缓冲大小确定(基于网络延迟)。谢谢!

以上是关于如何在 iOS 中播放来自服务器的流式 PCM 数据?的主要内容,如果未能解决你的问题,请参考以下文章

通过 tcp 套接字流式传输 PCM 音频

在 C++ 中连续流式传输 PCM 数据?

如何设置 AudioStreamBasicDescription 属性?

在 Node.js 上从 Web Audio API 播放 PCM 流

如何将 PCM 音频流转换为在线播放

如何在 iOS 中添加带有 PCM 数据/缓冲区的可播放(如 wav、wmv)标头?