整个早上我都在为这个问题苦思冥想。
我已经建立了一个返回音频数据的数据源连接(它是一个录音设备,所以数据没有设置长度。数据只是流入。就像,如果你打开一个流到 radio )
并且我已经成功地在我的代码中接收到所有数据包。现在我只需要玩它。我想播放传入的数据,所以我不想排队等几分钟,我想使用我当时收到的数据并播放它。
现在我整个上午都在寻找不同的例子,但没有一个是真正的。
在
- (void)connection:(NSURLConnection )connection didReceiveData:(NSData)data {
函数,“数据”包就是音频包。我尝试使用 AVPlayer、MFVideoPlayer 对其进行流式传输,但到目前为止对我没有任何效果。还尝试查看 mattgallagher 的 Audiostreamer,但仍然无法实现。
这里的任何人都可以提供帮助,有一些(最好)工作示例吗?
最佳答案
注意:只有当您从服务器接收到 PCM 数据时,下面的答案才有效。这当然是永远不会发生的。这就是为什么在呈现音频和接收数据之间需要另一个步骤:数据转换。
根据格式的不同,这可能或多或少有些棘手,但通常您应该在此步骤中使用音频转换器服务。
你应该使用 -(void)connection:(NSURLConnection )connection didReceiveData:(NSData)data
来填充来自服务器的数据的缓冲区,播放它不应该有任何东西用这个方法做。
现在,要使用缓冲区播放您“存储”在内存中的数据,您需要使用 RemoteIO 和音频单元。 Here is a good, comprehensive tutorial .您可以从教程中删除“记录”部分,因为您并不真正需要它。
如你所见,他们定义了一个回放回调:
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = self;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
kOutputBus,
&callbackStruct,
sizeof(callbackStruct));
和playbackCallback
函数如下所示:
static OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
for (int i = 0 ; i < ioData->mNumberBuffers; i++){
AudioBuffer buffer = ioData->mBuffers[i];
unsigned char *frameBuffer = buffer.mData;
for (int j = 0; j < inNumberFrames*2; j++){
frameBuffer[j] = getNextPacket();//this here is a function you have to make to get the next chunk of bytes available in the stream buffer
}
}
return noErr;
}
基本上它所做的是用下一个需要播放的字节 block 填充 ioData
缓冲区。如果没有要播放的新数据,请确保将 ioData
缓冲区清零(静音)(如果流缓冲区中没有足够的数据,播放器将静音)。
此外,您可以使用 alSourceQueueBuffers
和 alSourceUnqueueBuffers
将缓冲区一个接一个地排队,从而实现与 OpenAL 相同的效果。
就是这样。编码愉快!
关于iphone - 从连续的数据流中播放音频 (iOS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6611151/