如何使用 AVAudioRecorder 恢复录音?

发布于 2024-10-18 11:17:04 字数 424 浏览 1 评论 0原文

我正在编写一个使用 AVAudioRecorder 类的应用程序。它工作得很好,除非有电话打进来。我正在根据苹果使用 AVAudioRecorderDelegate 方法的指南来处理它。

– (void) audioRecorderBeginInterruption:
– (void) audioRecorderEndInterruption:

它工作得很好,直到中断结束,我尝试通过再次调用记录方法来“恢复”录音(根据文档) )。然而,它不会恢复我的录音,而是丢弃旧的录音并在其位置启动一个全新的录音。我一直无法找到这个问题的解决方案,如果有人解决了这个问题,或者如果这是苹果 AVAudioRecorder 的错误,请告诉我。我真的希望我不必使用 AudioQueues 来编写此内容。

谢谢

I am writing an application that uses the AVAudioRecorder class. It works great except for when a phone call comes in. I am handling this per apple's guidelines of using the AVAudioRecorderDelegate methods

– (void) audioRecorderBeginInterruption:
– (void) audioRecorderEndInterruption:

It works great until the interruption ends and I attempt to "resume" the recording by calling the record method again (per the documentation). However it does not resume my recording but instead throws out the old one and starts up an entirely new one in its place. I have not been able to find a solution to this problem, if anyone has figured this out, or if it is a bug with apple's AVAudioRecorder please let me know. I really hope I do not have to write this using AudioQueues.

thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

泪意 2024-10-25 11:17:04

看起来这是苹果 API 的一个错误。非常有趣......

这是我们从支持票中收到的回复。

“您描述的行为是一个错误,不幸的是,API 中没有任何内容可供您更改以实际附加到原始录音中。中断导致仅捕获中断后录制的音频。您可以尝试停止中断后进行记录,然后创建一个新文件,这至少不会导致用户丢失任何信息,但结果将是两个单独的文件,

请为此问题提交错误报告,因为外部开发人员提交的错误在以下情况下至关重要。 iOS 工程正在评估要解决的修复的关键功能,它很容易重现,但如果您有一个测试应用程序,请包括在内,iOS 工程就像直接显示错误的应用程序一样。

Looks like its a bug with apple's API. Great fun....

This was the response we received from a support ticket.

"The behavior you described is a bug and unfortunately there's nothing in the API that you can change to work around to actually append to the original recording. The interruption is resulting in capturing only the audio recorded after the interruption. You could try and stop the recording after the interruption then creating a new file after which would at least not cause the user to loose any information, but the result would be two separate files.

Please file a bug report at for this issue since bugs filed by external developers are critical when iOS engineering is evaluating critical features of fixes to address. It's easily reproducible but if you have a test app you can include please do, iOS engineering like having apps that show the bug directly.
"

听风念你 2024-10-25 11:17:04

实际上不存在错误(至少不再存在)。该方法的当前文档 (2023) 指出,调用 .record() 将隐式调用 .prepareToRecord(),从而在指定的 URL 处创建一个新文件。 Apple 的文档明确指出,如果 URL 处存在文件,它将被覆盖。换句话说,使用提供的 API 不可能“恢复”记录。使用 AVAudioRecorder 实现此目的的唯一方法是创建多个文件并合并它们。应该注意的是,Apple 的 AVAudioRecorder.record() 文档具有误导性,因为它实际上说的是“开始或恢复音频录制”。

https://developer.apple.com/documentation/avfaudio/avaudiorecorder/1388252-记录
https://developer.apple.com/documentation/avfaudio/avaudiorecorder/1389435-准备录制

There isn't actually a bug (at least not anymore). The current documentation (2023) for the method states that calling .record() will implicitly call .prepareToRecord() which creates a NEW file at the specified URL. Apple's docs clearly state that if a file exists at the URL it will be overwritten. In other words, "resuming" recording is impossible with the provided APIs. The only way to achieve this with AVAudioRecorder is to create multiple files and merge them. It should be noted that Apple's documentation of AVAudioRecorder.record() is misleading as it does in fact say "Starts or resumes audio recording".

https://developer.apple.com/documentation/avfaudio/avaudiorecorder/1388252-record
https://developer.apple.com/documentation/avfaudio/avaudiorecorder/1389435-preparetorecord

云之铃。 2024-10-25 11:17:04

我的解决方案是:

  1. 在临时文件上开始记录

  2. 监视 AVAudioSessionInterruptionNotificatio

  3. On AVAudioSessionInterruptionTypeBegan - 停止录制。
  4. 在 AVAudioSessionInterruptionTypeEnded 上 - 开始新的录制。
  5. 当用户停止时 - 标记文件。

完整代码

     [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(audioSessionInterruptionNotification:)
                                             name:AVAudioSessionInterruptionNotification
                                           object:audioSession];



    -(void)audioSessionInterruptionNotification:(NSNotification*)notification {
    NSString* seccReason = @"";
    //Check the type of notification, especially if you are sending multiple AVAudioSession events here
    NSLog(@"Interruption notification name %@", notification.name);
    NSError *err = noErr;
    if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
    seccReason = @"Interruption notification received";

    //Check to see if it was a Begin interruption
    if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
        seccReason = @"Interruption began";
        NSLog(@"Interruption notification name %@ audio pause", notification.name);

        dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW,
                                                    0.01 * NSEC_PER_SEC);
        dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{
            AVAudioRecorder *recorder = [[self recorderPool] objectForKey:lastRecID];
            if (recorder) {
                if(recorder.isRecording) {
                    [recorder stop];
                    NSLog(@"Interruption notification name Pauseing recording %@", lastRecID);
                } else {
                    NSLog(@"Interruption notification name Already Paused %@", lastRecID);
                }
            }else {
                NSLog(@"Interruption notification name recording %@ not found", lastRecID);
            }
              NSLog(@"Interruption notification Pauseing recording status %d",recorder.isRecording);
        });

    } else if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
        seccReason = @"Interruption ended!";
         NSLog(@"Interruption notification name %@ audio resume", notification.name);
        //Start New Recording
        dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW,
                                                    0.1 * NSEC_PER_SEC);
        dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{
            AVAudioRecorder *recorder = [[self recorderPool] objectForKey:lastRecID];
            NSLog(@"Interruption notification Resumeing recording status %d",recorder.isRecording);
            if (recorder) {
                if(!recorder.isRecording) {
                    NSString *filePath = [[self orgFileNames] objectForKey:lastRecID];
                    NSArray * fileNames =[[self fileNames] objectForKey:lastRecID];
                    NSString *tmpFileName = [self gnrTempFileName:filePath AndNumber:fileNames.count];
                    [[[self fileNames] objectForKey:lastRecID] addObject:tmpFileName];
                    NSURL *url = [NSURL fileURLWithPath:tmpFileName];
                    NSError *error = nil;
                    recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&error];
                    if (![recorder record]) {
                        NSLog(@"Interruption notification Error Resumeing recording %@",tempRecorder);
                        return;
                    }
                    [[self recorderPool] setObject:recorder forKey:lastRecID];
                    NSLog(@"Interruption notification nameResumeing recording %@",lastRecID);
                }else {
                     NSLog(@"Interruption notification Already Recording %d",recorder.isRecording);
                }
            }else {
                NSLog(@"Interruption notification name recording %@ not found",lastRecID);
            }
        });
      }
     } 
    }

My solution was:

  1. Start record on temp file

  2. Watch for AVAudioSessionInterruptionNotificatio

  3. On AVAudioSessionInterruptionTypeBegan - stop the recording.
  4. On AVAudioSessionInterruptionTypeEnded - Start new recording.
  5. When the user stops - Marge the files.

Full Code

     [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(audioSessionInterruptionNotification:)
                                             name:AVAudioSessionInterruptionNotification
                                           object:audioSession];



    -(void)audioSessionInterruptionNotification:(NSNotification*)notification {
    NSString* seccReason = @"";
    //Check the type of notification, especially if you are sending multiple AVAudioSession events here
    NSLog(@"Interruption notification name %@", notification.name);
    NSError *err = noErr;
    if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
    seccReason = @"Interruption notification received";

    //Check to see if it was a Begin interruption
    if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
        seccReason = @"Interruption began";
        NSLog(@"Interruption notification name %@ audio pause", notification.name);

        dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW,
                                                    0.01 * NSEC_PER_SEC);
        dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{
            AVAudioRecorder *recorder = [[self recorderPool] objectForKey:lastRecID];
            if (recorder) {
                if(recorder.isRecording) {
                    [recorder stop];
                    NSLog(@"Interruption notification name Pauseing recording %@", lastRecID);
                } else {
                    NSLog(@"Interruption notification name Already Paused %@", lastRecID);
                }
            }else {
                NSLog(@"Interruption notification name recording %@ not found", lastRecID);
            }
              NSLog(@"Interruption notification Pauseing recording status %d",recorder.isRecording);
        });

    } else if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
        seccReason = @"Interruption ended!";
         NSLog(@"Interruption notification name %@ audio resume", notification.name);
        //Start New Recording
        dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW,
                                                    0.1 * NSEC_PER_SEC);
        dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{
            AVAudioRecorder *recorder = [[self recorderPool] objectForKey:lastRecID];
            NSLog(@"Interruption notification Resumeing recording status %d",recorder.isRecording);
            if (recorder) {
                if(!recorder.isRecording) {
                    NSString *filePath = [[self orgFileNames] objectForKey:lastRecID];
                    NSArray * fileNames =[[self fileNames] objectForKey:lastRecID];
                    NSString *tmpFileName = [self gnrTempFileName:filePath AndNumber:fileNames.count];
                    [[[self fileNames] objectForKey:lastRecID] addObject:tmpFileName];
                    NSURL *url = [NSURL fileURLWithPath:tmpFileName];
                    NSError *error = nil;
                    recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&error];
                    if (![recorder record]) {
                        NSLog(@"Interruption notification Error Resumeing recording %@",tempRecorder);
                        return;
                    }
                    [[self recorderPool] setObject:recorder forKey:lastRecID];
                    NSLog(@"Interruption notification nameResumeing recording %@",lastRecID);
                }else {
                     NSLog(@"Interruption notification Already Recording %d",recorder.isRecording);
                }
            }else {
                NSLog(@"Interruption notification name recording %@ not found",lastRecID);
            }
        });
      }
     } 
    }
驱逐舰岛风号 2024-10-25 11:17:04

您将尝试使用这段代码

-(IBAction)pauseandplay:(id)sender
{
    BOOL status= [player isPlaying];
    if(status)
    {
    [pauseplay setImage:[UIImage imageNamed:@"play.png"]];
    [player pause];
    }
    else
    {
    [pauseplay setImage:[UIImage imageNamed:@"icon-pause.png"]];
    [player play];
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(updateCurrentTime) userInfo:player repeats:YES];
    }
}

You will try by using this piece of code

-(IBAction)pauseandplay:(id)sender
{
    BOOL status= [player isPlaying];
    if(status)
    {
    [pauseplay setImage:[UIImage imageNamed:@"play.png"]];
    [player pause];
    }
    else
    {
    [pauseplay setImage:[UIImage imageNamed:@"icon-pause.png"]];
    [player play];
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(updateCurrentTime) userInfo:player repeats:YES];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文