音频队列服务提供一个可能,那就是:把音频数据块填充到音频队列服务缓冲区中,从而达到播放声音的目的,这种方式很类似 Windows 中的 waveOutWrite 方法。这样,我们就可以通过这个方法实现播放从网络上传输过来的音频数据。
我们需要通过队列服务提供的 AQOutputCallback 回调中填充缓冲区,在这里,我们就可以填充从网络传输过来的数据。
参看代码:
AudioStreamBasicDescription format; // 声音格式设置,这些设置要和采集时的配置一致
memset(&format, 0, sizeof(format));
format.mSampleRate = 44100; // 采样率 (立体声 = 8000)
format.mFormatID = kAudioFormatLinearPCM; // PCM 格式
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
format.mChannelsPerFrame = 1; // 1:单声道;2:立体声
format.mBitsPerChannel = 16; // 语音每采样点占用位数
format.mBytesPerFrame = (format.mBitsPerChannel / * format.mChannelsPerFrame;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
AudioQueueRef queue;
AudioQueueNewOutput(&format,
AQPlayer::AQOutputCallback,
this, // opaque reference to whatever you like
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&queue);
const int bufferSize = 0xA000; // 48K - around 1/2 sec of 44kHz 16 bit mono PCM
for (int i = 0; i < kNumberBuffers; ++i)
AudioQueueAllocateBufferWithPacketDescriptions(queue, bufferSize, 0, &mBuffers[i]);
AudioQueueSetParameter(queue, kAudioQueueParam_Volume, 1.0);
UInt32 category = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
AudioSessionSetActive(true);
// prime the queue with some data before starting
for (int i = 0; i < kNumberBuffers; ++i)
OutputCallback(queue, mBuffers[i]);
AudioQueueStart(queue, NULL);
在CallBack中填出数据:
void OutputCallback(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) {
// Fill
//AQPlayer* that = (AQPlayer*) inUserData;
inCompleteAQBuffer->mAudioDataByteSize = next->mAudioDataBytesCapacity;
for (int i = 0; i < inCompleteAQBuffer->mAudioDataByteSize; ++i)
next->mAudioData[i] = rand();
AudioQueueEnqueueBuffer(queue, inCompleteAQBuffer, 0, NULL);
}
音频采集参看:http://developer.apple.com/library/ios/#documentation/MusicAudio/Conceptual/
我们需要通过队列服务提供的 AQOutputCallback 回调中填充缓冲区,在这里,我们就可以填充从网络传输过来的数据。
参看代码:
AudioStreamBasicDescription format; // 声音格式设置,这些设置要和采集时的配置一致
memset(&format, 0, sizeof(format));
format.mSampleRate = 44100; // 采样率 (立体声 = 8000)
format.mFormatID = kAudioFormatLinearPCM; // PCM 格式
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
format.mChannelsPerFrame = 1; // 1:单声道;2:立体声
format.mBitsPerChannel = 16; // 语音每采样点占用位数
format.mBytesPerFrame = (format.mBitsPerChannel / * format.mChannelsPerFrame;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
AudioQueueRef queue;
AudioQueueNewOutput(&format,
AQPlayer::AQOutputCallback,
this, // opaque reference to whatever you like
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&queue);
const int bufferSize = 0xA000; // 48K - around 1/2 sec of 44kHz 16 bit mono PCM
for (int i = 0; i < kNumberBuffers; ++i)
AudioQueueAllocateBufferWithPacketDescriptions(queue, bufferSize, 0, &mBuffers[i]);
AudioQueueSetParameter(queue, kAudioQueueParam_Volume, 1.0);
UInt32 category = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
AudioSessionSetActive(true);
// prime the queue with some data before starting
for (int i = 0; i < kNumberBuffers; ++i)
OutputCallback(queue, mBuffers[i]);
AudioQueueStart(queue, NULL);
在CallBack中填出数据:
void OutputCallback(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) {
// Fill
//AQPlayer* that = (AQPlayer*) inUserData;
inCompleteAQBuffer->mAudioDataByteSize = next->mAudioDataBytesCapacity;
for (int i = 0; i < inCompleteAQBuffer->mAudioDataByteSize; ++i)
next->mAudioData[i] = rand();
AudioQueueEnqueueBuffer(queue, inCompleteAQBuffer, 0, NULL);
}
音频采集参看:http://developer.apple.com/library/ios/#documentation/MusicAudio/Conceptual/
AudioQueueProgrammingGuide/AQRecord/RecordingAudio.html
http://blog.youkuaiyun.com/ch_soft/article/details/7661505