简体   繁体   English

iOS应用程序在后台录制时音频中断

[英]Audio interruption when iOS application is recording in background

My iPad sound application (iOS 7.1) is able to record while in background. 我的iPad声音应用程序(iOS 7.1)可以在后台录制。 Everything is ok as far as recording is not interrupted while in background. 只要在后台录制不中断,一切都可以。 For example if one's has the (stupid?) idea to start listening music while recording something. 例如,如果某人有(愚蠢的?)想法在录音时开始聆听音乐。

I tried to manage this interruption in different ways, with no success. 我试图以不同的方式来处理这种中断,但没有成功。 The problem is that the 问题是

  - (void)audioRecorderEndInterruption:(AVAudioPlayer *)p withOptions:(NSUInteger)flags

is never fired when application was in background as the interruption occurred. 当应用程序在后台发生中断时,永远不会触发它。 I then tried, in another solution, to implement the AVAudioSessionInterruptionNotification and a handleInterruption: method as 然后,我尝试在另一种解决方案中,实现AVAudioSessionInterruptionNotification和handleInterruption:方法为

- (void) viewDidAppear:(BOOL)animated
{
......
AVAudioSession *session=[AVAudioSession sharedInstance];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleInterruption:)
                                             name:AVAudioSessionInterruptionNotification
                                           object:session];
.......
}
// interruption handling

- (void)handleInterruption:(NSNotification *)notification
{
    try {
        UInt8 theInterruptionType = [[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue];
        NSLog(@"Session interrupted > --- %s ---\n", theInterruptionType == AVAudioSessionInterruptionTypeBegan ? "Begin Interruption" : "End Interruption");

        .... MANAGE interruption begin    
        interruptionBeganWhileInBackgroundMode = TRUE;

        }            
        if (theInterruptionType == AVAudioSessionInterruptionTypeEnded) {

        .... MANAGE interruption end

        }
    } catch (CAXException e) {
        char buf[256];
        fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
    }
}

In this case the handleInterruption: is fired when interruption begins, but it is not when interruption ends (shoulld be fired with theInterruptionType set to AVAudioSessionInterruptionTypeEnded) 在这种情况下,在中断开始时会触发handleInterruption:,但在中断结束时不会触发(应在将InterruptionType设置为AVAudioSessionInterruptionTypeEnded的情况下触发)

To circumvent this problem, I decided to set a flag ( interruptionBeganWhileInBackgroundMode ) when interruption begins to get the application informed that an interruption has occurred when coming foreground. 为了解决这个问题,我决定在中断开始时设置一个标志( interruptBeganWhileInBackgroundMode ),以使应用程序得知在进入前台时发生了中断。 So that I can manage the end of interruption. 这样我就可以管理中断的结束了。

It may seem clever, but it is not! 它看起来很聪明,但事实并非如此! Here is why... 这就是为什么

I tried two implementations. 我尝试了两种实现。

Solution 1 . 解决方法1 Put a [recorder pause] in handleInterruption: when interruption begins, and manage a [recorder record] in the comingForeground: method when the interruption flag is set. 在中断开始时,将[记录器暂停]放入handleInterruption:中,并在设置了中断标志时在comeingForeground:方法中管理[记录器记录]。 In this situation, the recording is going on immediately when application comes back to foreground, BUT instead of resuming, the recorder erase the file and restart a new recording, so that everything recorded before interruption is lost . 在这种情况下,当应用程序返回到前台时,录制会立即继续进行, 但不是恢复,而是由录制器擦除文件并重新开始新的录制,因此中断之前录制的所有内容都会丢失

Solution 2 . 解决方案2 Put a [recorder stop] in handleInterruption: when interruption begins, to save the file, to be sure to preserve the recorded data. 在handleInterruption中放置[recorder stop]:当中断开始时,要保存文件,以确保保留记录的数据。 This recording is saved, BUT when application is coming foreground, it stalls for about ten seconds before the user can interact again , as if there was a process (the file saving?) that keep the UI frozen. 该记录已保存, 但是当应用程序进入前台时,它将停顿约十秒钟,然后用户才能再次进行交互 ,就好像有一个使UI冻结的进程(保存文件?)一样。

Last point: I have exactly the same problems in iPhone version of this application: when application is foreground and a phone call occurs, everything goes OK. 最后一点:在此应用程序的iPhone版本中,我有完全相同的问题:当应用程序为前台且发生电话时,一切正常。 But when a phone call occurs as my application is background I see the same bad behaviour as in iPad's version. 但是,当我的应用程序处于后台时发生电话呼叫时,我会看到与iPad版本相同的不良行为。

I notice that Apple's Voice Memo app in iOS7 correctly manage these background interruptions (it stops and saves the recording) despite it displays a 00:00:00 file length when coming foreground. 我注意到,iOS7中的Apple 语音备忘录应用程序可以正确管理这些背景中断(它停止并保存录音),尽管它在进入前景时显示00:00:00文件长度。 The iTalk application manages it perfectly, automatically resuming recording when coming foreground. iTalk应用程序可以完美地管理它,当到达前台时会自动恢复记录。

Did anybody find a workaround for the audio interruption management for backgrounded recording applications? 是否有人为后台录制应用程序的音频中断管理找到解决方法? I found plenty of people looking for that in many developer websites, but no answer... Thanks! 我在许多开发者网站上找到了很多人在寻找它,但是没有答案……谢谢!

I have been going through the same issue myself. 我本人也一直在经历同样的问题。 It seems as if there is a bug in the iOS7 AVAudioRecorder in how it deals with interrupts. 似乎iOS7 AVAudioRecorder中存在一个如何处理中断的错误。 Instead of pausing as I believe the documentation says that is should, it closes the file. 它不会关闭文件,而是像我认为文档所述那样暂停了文件。 I have not been able to figure out what is stalling the app when it comes back to the foreground. 我还无法弄清是什么原因使应用程序重新回到前台。 In my case, I would see AVAudioRecorder finish (with the success flag set to NO), after 10 seconds. 就我而言,我会在10秒钟后看到AVAudioRecorder完成(成功标志设置为NO)。

I ended up rewriting the audio recorder using Audio Queues. 我最终使用Audio Queues重写了录音机。 I found some sample code here (git@github.com:vecter/Audio-Queue-Services-Example.git) that helped with setting it up in an Objective-C environment and the Apple SpeakHere demo has some code to handle the interrupt notifications. 我在这里(git@github.com:vecter / Audio-Queue-Services-Example.git)找到了一些示例代码,这些示例代码有助于在Objective-C环境中进行设置,Apple SpeakHere演示包含一些代码来处理中断通知。

Essentially, I am stopping the recording on interrupt began and opening an alert for the user to save the file. 本质上,我是在中断开始时停止记录,并为用户打开一个警报以保存文件。 This alert is deferred until UIApplicationDidBecomeActiveNotification is passed if the interrupt started while the app was in the background. 如果在应用程序处于后台运行时启动了中断,则此警报将推迟到通过UIApplicationDidBecomeActiveNotification为止。

One other thing to note, there seems to be a minor bug in Audio Queues that the AudioQueueStart method will return -50 sometimes. 还要注意的另一件事是,音频队列中似乎有一个小错误,有时AudioQueueStart方法将返回-50。 If you add 如果添加

AudioSessionInitialize(NULL, NULL,nil,(__bridge  void *)(self));
UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
                        sizeof(sessionCategory),
                        &sessionCategory
                        );
AudioSessionSetActive(true);

Before any AudioQueue methods, the error goes away. 在使用任何AudioQueue方法之前,错误都会消失。 These methods are marked as deprecated but seem to be necessary. 这些方法被标记为已弃用,但似乎是必需的。

Don't know / think this is going to be relevant to the original author of the topic, but here is my experience with it: 不知道/认为这将与该主题的原始作者有关,但是这是我的经验:

I ended up here because of the AVAudioSessionInterruptionNotification thing; 由于AVAudioSessionInterruptionNotification的缘故,我到了这里。 the .began flavour came as expected, but the .ended one did not. .began风味符合预期,但.end风味没有。 In my case, it happened because I was using two AVPlayer instances: one to play music, and the other one to play silence while the first struggled to start streaming a new track (otherwise iOS would suspend my app while in background, if next track loading did not happen fast enough). 就我而言,这是因为我使用了两个AVPlayer实例:一个用于播放音乐,另一个用于静音,而第一个实例则努力开始播放新曲目(否则,如果下一首曲目,iOS将在后台暂停我的应用程序加载速度不够快)。

Turns out it's not the brightest solution, and it somehow messes up the notification system. 事实证明,这不是最聪明的解决方案,并且以某种方式弄乱了通知系统。 Giving up the second AVPlayer (the silence playing one) resulted in .ended being triggered as expected. 放弃第二个AVPlayer(静音播放其中一个)导致.end被按预期方式触发。 Of course, I found the answer / solution for the notification problem, but I'm now left with the old one... :-) 当然,我找到了通知问题的答案/解决方案,但现在剩下的是旧的... :-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM