标签: audioqueue

在iOS中实现和排除背景音频

StackOverflow上有很多关于iOS背景音乐播放的问题.没有完全探索所有边缘情况,这个问题的目的是成为iOS背景音频问题的最后一个词

定义和假设

所有代码,问题和示例均参考.

"背景" - 当用户按下主页按钮或电源按钮时应用程序的状态(因此设备显示锁定屏幕).该应用程序还可以使用多任务切换器或iPad上的多任务手势进入后台.

"audio" - 使用AudioQueue播放的音频(包括AVAudioPlayer)

先决条件

据我了解,有一个要求让应用程序在后台播放音频.

  1. 设置UIBackgroundModesaudioInfo.plist
  2. [[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)

边缘案例

  1. 中断.如果您注册成为音频中断(电话等)的通知,则成为其代表AVAudioPlayer.例如,如果您在中断开始时暂停或停止音频,则在结束时恢复,如果中断超过10分钟(后台任务完成的最长时间),您的应用程序将被暂停?

  2. 如果调用Lock或Home,模拟器将停止音频,同时使用:

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    Run Code Online (Sandbox Code Playgroud)

但是这适用于设备.这是一个已知的问题?

iphone avaudioplayer audioqueue avaudiosession ios5

15
推荐指数
1
解决办法
2498
查看次数

如何从iOS中的AudioQueueRef获取浮点音频数据数组?

我正在努力将音频传输到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)

objective-c core-audio avaudiorecorder audioqueue ios

13
推荐指数
1
解决办法
3454
查看次数

从未调用过CoreAudio AudioQueue回调函数,没有报告错误

我试图从文件功能做一个简单的回放,似乎我的回调函数永远不会被调用.它并没有真正意义,因为所有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)

macos objective-c callback core-audio audioqueue

13
推荐指数
1
解决办法
2971
查看次数

中断后AudioSessionSetActive失败

我试图弄清楚实际发生了几周的事情,我不知道为什么我不能在中断后继续播放,所以你们可能知道答案.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,如果它能帮助以某种方式解决问题..

iphone objective-c audioqueue interruption

8
推荐指数
1
解决办法
5768
查看次数

OSX中的AEC(回声消除支持)使用AudioQueue

我正在开发OSX和iOS上的VOIP应用程序,并将使用AudioQueue for Audio流程,想要知道的是,默认情况下,AudioQueue支持声学回声消除,或者我们是否需要添加对它的支持,
如果我们需要实现,我相信一些开源库必须像Speex一样实现有任何可用的示例显示AudioQueue与Speex或任何其他库的集成

macos cocoa objective-c audioqueue echo-cancellation

8
推荐指数
1
解决办法
8113
查看次数

音频队列播放完成的精确时间

我正在使用音频队列来播放音频文件.我需要精确计时最后一个缓冲区.我需要在播放最后一个缓冲区后的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)

objective-c core-audio audioqueueservices audioqueue ios

8
推荐指数
1
解决办法
1929
查看次数

如何在ios中使用AudioQueue编码/解码speex

如果有人有一些使用AudioQueue编码/解码speex音频格式的经验?

我试图通过编辑SpeakHere示例来实现它.但不成功!

从Apple API文档中,AudioQueue可以支持编解码器,但我找不到任何样本.有人能给我一些建议吗?我已经在XCode 4的项目中成功编译了speex编解码器.

iphone codec speex audioqueue ios

6
推荐指数
1
解决办法
3782
查看次数

使用AudioQueue在iOS上进行扭曲(机器人)音频录制

我正在AudioQueueiOS中使用以实现对网络的录制流.

问题是它通常效果很好,但有时(约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)

audio-recording audioqueue ios

6
推荐指数
1
解决办法
542
查看次数

缓冲区大小较小时,音频队列播放速度过快

我能够使用音频文件服务+音频队列服务流式传输和播放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)

buffer objective-c audioqueueservices audioqueue ios

6
推荐指数
1
解决办法
1723
查看次数

如何设置AudioStreamBasicDescription属性?

我正在尝试使用 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,,mBytesPerFramemBytesPerPacket我看过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)

pcm audioqueue ios

5
推荐指数
1
解决办法
4111
查看次数