StackOverflow上有很多关于iOS背景音乐播放的问题.没有完全探索所有边缘情况,这个问题的目的是成为iOS背景音频问题的最后一个词
所有代码,问题和示例均参考ios5.
"背景" - 当用户按下主页按钮或电源按钮时应用程序的状态(因此设备显示锁定屏幕).该应用程序还可以使用多任务切换器或iPad上的多任务手势进入后台.
"audio" - 使用AudioQueue播放的音频(包括AVAudioPlayer)
据我了解,有一个要求让应用程序在后台播放音频.
UIBackgroundModes
于audio
在Info.plist
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
我的用例是在后台播放相对较长的音频(音乐).可能有数百个曲目,应用程序将按顺序播放它们.可以认为音频将无限播放.
该应用程序将通过暂停播放来处理中断.
我的成功喜忧参半:
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:...];
Run Code Online (Sandbox Code Playgroud)
允许音频在后台播放.但是我很困惑它是否需要以及它与以下内容的区别:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
Run Code Online (Sandbox Code Playgroud)
中断.如果您注册成为音频中断(电话等)的通知,则成为其代表AVAudioPlayer
.例如,如果您在中断开始时暂停或停止音频,则在结束时恢复,如果中断超过10分钟(后台任务完成的最长时间),您的应用程序将被暂停?
如果调用Lock或Home,模拟器将停止音频,同时使用:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
Run Code Online (Sandbox Code Playgroud)但是这适用于设备.这是一个已知的问题?
我正在努力将音频传输到iPhone中,我可以将其传递给(C++)分析算法.当然,有很多选择:在trailinthes上的AudioQueue教程并开始工作.
然而,音频回调给出了一个AudioQueueRef
,我发现Apple的文档在这方面很薄.内置方法可以写入文件,但实际上您不会在数据包内部查找数据.
我需要数据.我不想在文件中写任何内容,这就是所有教程 - 甚至Apple的便利I/O对象 - 似乎都是针对的.Apple AVAudioRecorder
(激怒)会给你级别并写入数据,但实际上并没有让你访问它.除非我遗漏了什么......
这该怎么做?在下面的代码中有inBuffer->mAudioData
一个非常接近,但我找不到有关这个'数据'的格式或如何访问它的信息.
AudioQueue回调:
void AudioInputCallback(void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription *inPacketDescs)
{
static int count = 0;
RecordState* recordState = (RecordState*)inUserData;
AudioQueueEnqueueBuffer(recordState->queue, inBuffer, 0, NULL);
++count;
printf("Got buffer %d\n", count);
}
Run Code Online (Sandbox Code Playgroud)
以及将音频写入文件的代码:
OSStatus status = AudioFileWritePackets(recordState->audioFile,
false,
inBuffer->mAudioDataByteSize,
inPacketDescs,
recordState->currentPacket,
&inNumberPacketDescriptions,
inBuffer->mAudioData); // THIS! This is what I want to look inside of.
if(status == 0)
{
recordState->currentPacket += …
Run Code Online (Sandbox Code Playgroud) 我试图从文件功能做一个简单的回放,似乎我的回调函数永远不会被调用.它并没有真正意义,因为所有OSStatus都返回0,其他数字也都显示正确(就像输出数据包从AudioFileReadPackets读取指针).
这是设置:
OSStatus stat;
stat = AudioFileOpenURL(
(CFURLRef)urlpath, kAudioFileReadPermission, 0, &aStreamData->aFile
);
UInt32 dsze = 0;
stat = AudioFileGetPropertyInfo(
aStreamData->aFile, kAudioFilePropertyDataFormat, &dsze, 0
);
stat = AudioFileGetProperty(
aStreamData->aFile, kAudioFilePropertyDataFormat, &dsze, &aStreamData->aDescription
);
stat = AudioQueueNewOutput(
&aStreamData->aDescription, bufferCallback, aStreamData, NULL, NULL, 0, &aStreamData->aQueue
);
aStreamData->pOffset = 0;
for(int i = 0; i < NUM_BUFFERS; i++) {
stat = AudioQueueAllocateBuffer(
aStreamData->aQueue, aStreamData->aDescription.mBytesPerPacket, &aStreamData->aBuffer[i]
);
bufferCallback(aStreamData, aStreamData->aQueue, aStreamData->aBuffer[i]);
}
stat = AudioQueuePrime(aStreamData->aQueue, 0, NULL);
stat = AudioQueueStart(aStreamData->aQueue, NULL);
Run Code Online (Sandbox Code Playgroud)
(未显示的是我正在检查stat
函数之间的值,它只是恢复正常.)
和回调函数:
void …
Run Code Online (Sandbox Code Playgroud) 我试图弄清楚实际发生了几周的事情,我不知道为什么我不能在中断后继续播放,所以你们可能知道答案.AudioSessionSetActive(TRUE)总是返回'!cat',这是kAudioSessionIncompatibleCategory,重新激活,如果我的应用程序在后台播放,我在不同的应用程序.虽然它工作正常并且如果我在我的应用程序中发现中断时继续播放.
原始代码实际上包含在宏中包含的所有AudioSession和AudioQueue调用,如果它意味着错误,则打印OSStatus,但我删除它以获得更好的可读性.此外,[self pause]只是暂停,所以基本上它会在upause时调用AudioQueueStart(audioQueue,NULL)但是如果AudioSession失败则它不起作用.
音频会话初始化代码:
AudioSessionInitialize(NULL, NULL, _audioSessionInterruptionListener, self);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, _audioSessionPropertyListener, self);
AudioSessionSetActive(TRUE);
Run Code Online (Sandbox Code Playgroud)
中断处理程序代码:
- (void)handleInterruptionChangeToState:(AudioQueuePropertyID)inInterruptionState
{
if(inInterruptionState == kAudioSessionBeginInterruption)
{
NSLog(@"+Interruption");
if(self.state == NX_STATE_PLAY)
{
[self pause];
AudioSessionSetActive(FALSE);
isPausedByInterruption = YES;
}
}
else if(inInterruptionState == kAudioSessionEndInterruption)
{
if(isPausedByInterruption)
{
AudioSessionSetActive(TRUE);
[self pause];
isPausedByInterruption = FALSE;
}
NSLog(@"-Interruption");
}
}
Run Code Online (Sandbox Code Playgroud)
这个流媒体源代码可以在这里找到https://bitbucket.org/and/amaudiostreamer/src/122de41fe6c0/AMAudioStreamer/AMAudioStreamer/Classes/NxAudioStreamer.m,如果它能帮助以某种方式解决问题..
我正在开发OSX和iOS上的VOIP应用程序,并将使用AudioQueue for Audio流程,想要知道的是,默认情况下,AudioQueue支持声学回声消除,或者我们是否需要添加对它的支持,
如果我们需要实现,我相信一些开源库必须像Speex一样实现有任何可用的示例显示AudioQueue与Speex或任何其他库的集成
我正在使用音频队列来播放音频文件.我需要精确计时最后一个缓冲区.我需要在播放最后一个缓冲区后的150ms-200ms内通知一个函数...
通过回调方法我知道有多少缓冲区被排队
我知道缓冲区大小,我知道上一个缓冲区填充了多少字节.
首先,我初始化一些缓冲区,然后用音频数据填充缓冲区,然后将它们排队.当音频队列需要填充缓冲区时,它会调用回调并用缓冲区填充数据.
当没有更多可用的音频数据时,Audio Queue会向我发送最后一个空缓冲区,所以我用我拥有的任何数据填充它:
if (sharedCache.numberOfToTalPackets>0)
{
if (currentlyReadingBufferIndex==[sharedCache.baseAudioCache count]-1) {
inBuffer->mAudioDataByteSize = (UInt32)bytesFilled;
lastEnqueudBufferSize=bytesFilled;
err=AudioQueueEnqueueBuffer(inAQ,inBuffer,(UInt32)packetsFilled,packetDescs);
if (err) {
[self failWithErrorCode:err customError:AP_AUDIO_QUEUE_ENQUEUE_FAILED];
}
printf("if that was the last free packet description, then enqueue the buffer\n");
//go to the next item on keepbuffer array
isBufferFilled=YES;
[self incrementBufferUsedCount];
return;
}
}
Run Code Online (Sandbox Code Playgroud)
当音频队列通过回调要求更多数据并且我没有更多数据时,我开始倒计时缓冲区.如果缓冲区计数等于零,这意味着要播放的航班上只剩下一个缓冲区,则完成片刻播放时我会尝试停止音频队列.
-(void)decrementBufferUsedCount
{
if (buffersUsed>0) {
buffersUsed--;
printf("buffer on the queue %i\n",buffersUsed);
if (buffersUsed==0) {
NSLog(@"playback is finished\n");
// end playback
isPlayBackDone=YES;
double sampleRate = dataFormat.mSampleRate;
double bufferDuration = …
Run Code Online (Sandbox Code Playgroud) 如果有人有一些使用AudioQueue编码/解码speex音频格式的经验?
我试图通过编辑SpeakHere示例来实现它.但不成功!
从Apple API文档中,AudioQueue可以支持编解码器,但我找不到任何样本.有人能给我一些建议吗?我已经在XCode 4的项目中成功编译了speex编解码器.
我正在AudioQueue
iOS中使用以实现对网络的录制流.
问题是它通常效果很好,但有时(约20%的尝试)声音可怕的扭曲 - 它听起来像机器人.
编辑: 我能够在ios6和ios6.1模拟器上轻松地重现它 - 但我无法在真实手机(ios6.1.3)上重现它.
试图调试它我将PCM数据保存到文件.PCM文件中出现相同的失真,因此这在编码或上传代码中不是问题.我也尝试使用缓冲区的数量和缓冲区的大小 - 没有任何帮助.
问题是我不知道如何进一步调试它 - 看起来缓冲区被扭曲为回调的输入 - 在我的代码被激活之前(音频队列配置除外).
队列设置代码:
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mSampleRate = SAMPLE_RATE; //16000.0;
audioFormat.mChannelsPerFrame = CHANNELS; //1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mFramesPerPacket = 1;
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * sizeof(SInt16);
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
audioFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
| kLinearPCMFormatFlagIsPacked;
AudioQueueNewInput(
&audioFormat,
recordCallback,
self, // userData
CFRunLoopGetMain(), // run loop
NULL, // run loop mode
0, // flags
&recordQueue);
UInt32 trueValue = true;
AudioQueueSetProperty(recordQueue,kAudioQueueProperty_EnableLevelMetering,&trueValue,sizeof (UInt32)); …
Run Code Online (Sandbox Code Playgroud) 我能够使用音频文件服务+音频队列服务流式传输和播放m4a文件.由于文件类型,音频队列无法使用该文件的比特率信息.
下载完所有音频数据包后,我将它们提供给播放器.
当我选择一个大约32768或16384的缓冲区大小,因为回调被调用较少而且每个缓冲区大小很大,它似乎几乎以常规速度播放.问题有时我也要播放小文件但是当我选择小型缓冲区大小-512或1024或2048到8192时 - 音频播放速度非常快且偶尔会出现故障.
我知道在c回调中调用objective-c函数不是一个好主意,但为了可读性和易用性,我这样做.无论我认为这不是问题.
// allocate the buffers and prime the queue with some data before starting
AudioQueueBufferRef buffers[XMNumberPlaybackBuffers];
int i;
for (i = 0; i < XMNumberPlaybackBuffers; ++i)
{
err=AudioQueueAllocateBuffer(queue, XMAQDefaultBufSize, &buffers[i]);
if (err) {
[self failWithErrorCode:err customError:AP_AUDIO_QUEUE_BUFFER_ALLOCATION_FAILED];
}
@synchronized(self)
{
state=AP_WAITING_FOR_QUEUE_TO_START;
}
// manually invoke callback to fill buffers with data
MyAQOutputCallBack((__bridge void *)(self), queue, buffers[i]);
}
Run Code Online (Sandbox Code Playgroud)
我还从一个可变的字典中获取音频包...
#define XMNumberPlaybackBuffers 4
#define XMAQDefaultBufSize 8192
#pragma mark playback callback function
static void MyAQOutputCallBack(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 AudioQueue 从服务器播放 PCM 流数据。
PCM数据格式:
Sample rate = 48000, num of channel = 2, Bit per sample = 16
Run Code Online (Sandbox Code Playgroud)
并且,服务器不会将固定字节流式传输到客户端。(可变字节。)(例如:30848、128、2764、...字节)
如何设置ASBD?不知道怎么设置mFramesPerPacket
,,mBytesPerFrame
。mBytesPerPacket
我看过Apple的参考文档,但是没有详细的说明。
请给我任何想法。
新添加: 这里,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 …
Run Code Online (Sandbox Code Playgroud) audioqueue ×10
ios ×6
objective-c ×6
core-audio ×3
iphone ×3
macos ×2
buffer ×1
callback ×1
cocoa ×1
codec ×1
interruption ×1
ios5 ×1
pcm ×1
speex ×1