在 iOS 应用程序中,
使用
TPCircularBuffer
和 Audio Unit.
从 BLE 播放音频流
声音播放得很好,但是当缓冲区为空且没有字节可播放时,会产生噼啪声。
这是我的音频流配置,
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 8000.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsPacked;
// || kAudioFormatFlagsNativeFloatPacked || kAudioFormatFlagIsSignedInteger
//kAudioFormatFlagIsSignedInteger
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 32;// Update when required
audioFormat.mBytesPerPacket = 4; // Update when required
audioFormat.mBytesPerFrame = 4; // Update when required
下面是Audio Unit的播放功能
static OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
//1
for (int i=0; i < ioData->mNumberBuffers; i++) {
IosAudioController *THIS = (__bridge IosAudioController *)inRefCon;
int bytesAskingByPlayback = ioData->mBuffers[i].mDataByteSize;
SInt16 *targetBuffer = (SInt16*)ioData->mBuffers[i].mData;
// Pull audio from playthrough buffer
int32_t availableBytesFromBuffer;
SInt16 *sBuffer = TPCircularBufferTail(iosAudio.addressOfTPBuffer, &availableBytesFromBuffer);
int willRemainBytes = availableBytesFromBuffer - bytesAskingByPlayback;
if (willRemainBytes > 0) {
memcpy(targetBuffer, sBuffer, bytesAskingByPlayback);
TPCircularBufferConsume(iosAudio.addressOfTPBuffer,bytesAskingByPlayback);
} else {
//Note: Mostly need to update code here
memcpy(targetBuffer, sBuffer, availableBytesFromBuffer);
TPCircularBufferConsume(iosAudio.addressOfTPBuffer, availableBytesFromBuffer);
}
}
return noErr;
}
缓冲区大小为16384
一些解决方案说我会用 0 填充目标缓冲区以静音,但它不起作用。
一些解决方案说我可以用以前的值填充目标缓冲区以填补空白。
但是当缓冲区为空且没有字节可播放时。
您需要从这里开始并确定为什么会发生这种情况。理想情况下,这种情况永远不应该发生。如果确实发生了,那么这种情况应该很少见,并且有明确的原因。如果上游已经暂停,那么您需要暂停下游。如果存在网络延迟,那么您需要增加缓冲区的大小。
任何时候你注入一个常数值,无论是零还是最后收到的值,你都会注入高频噪声。这听起来像一声小爆裂声。如果你经常这样做,那么它就会破裂。有一些技术可以解决这个问题,但它们相当复杂,在解决潜在的运行不足问题之前,您不应该采用这些技术。
如果您的上游有可变的延迟,那么您需要在统计下游之前缓冲一点(10ms、50ms、2000ms,这取决于它的可变程度)。如果您的缓冲区已耗尽,您需要暂停下游,直到可以再次建立缓冲区。
有时,偶尔“弹出”以避免暂停下游是值得的,这时就会出现“用零填充”或“用最后一个值填充”之类的建议。但是,如果您每秒弹出多次(那就是通常是什么“噼啪声”),这可能意味着您在开始下游之前没有足够的缓冲。