如果电影之前已录制且已录制,AVAudioRecorder 将不会录制玩过

发布于 2024-10-01 19:10:20 字数 2302 浏览 0 评论 0原文

我的 iPhone 应用程序使用“AVAudioRecorder”进行录音。它还使用“UIImagePickerController”来录制电影,使用“MPMoviePlayerController”来播放电影。

一切正常,直到我连续完成所有三件事:

  1. 使用 UIImagePickerController 录制电影
  2. 使用 MPMoviePlayerController 播放录制的电影
  3. 尝试使用 AVAudioRecorder 进行录音

当我在步骤 3 中调用 AVAudioRecorder 的“record”方法时,它返回 NO 表示失败,但没有给出任何提示为什么(来吧苹果!) AVAudioRecorder 的 audioRecorderEncodeErrorDidOccur 委托方法从未被调用,并且在设置录音机时我没有收到其他错误。

我的第一个猜测是电影录制/播放正在修改“AVAudioSession”的共享实例,从而阻止录音机工作。但是,我手动将 AVAudioSession 的类别属性设置为“AVAudioSessionCategoryRecord”,并在尝试录制之前使音频会话处于活动状态。

这是我创建录音机的方法:

- (void)createAudioRecorder
{
 NSError *error = nil;
 AVAudioSession *audioSession = [AVAudioSession sharedInstance];
 [audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
 if (error)
  ...
 [audioSession setActive:YES error:&error];
 if (error)
  ...

 NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];

 // General Audio Format Settings 
 [settings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
 [settings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey]; 
 [settings setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];

 // Encoder Settings 
 [settings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey]; 
 [settings setValue:[NSNumber numberWithInt:96] forKey:AVEncoderBitRateKey]; 
 [settings setValue:[NSNumber numberWithInt:16] forKey:AVEncoderBitDepthHintKey];

 // Write the audio to a temporary file
 NSURL *tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"Recording.m4a"]];

 audioRecorder = [[AVAudioRecorder alloc] initWithURL:tempURL settings:settings error:&error];
 if (error)
  ...

 audioRecorder.delegate = self;
 if ([audioRecorder prepareToRecord] == NO)
  NSLog(@"Recorder fails to prepare!");

 [settings release];
}

这是我开始录音的方法:

- (void)startRecording
{
 if (!audioRecorder)
  [self createAudioRecorder];

 NSError *error = nil;
 [[AVAudioSession sharedInstance] setActive:YES error:&error];
 if (error)
  ...

 BOOL recording = [audioRecorder record];
 if (!recording)
  NSLog(@"Recording won't start!");
}

以前有人遇到过这个问题吗?

My iPhone app uses "AVAudioRecorder" to make voice recordings. It also uses "UIImagePickerController" to record movies and "MPMoviePlayerController" to play movies.

Everything works fine until I do all three things in a row:

  1. Record a movie using UIImagePickerController
  2. Play back the recorded movie using MPMoviePlayerController
  3. Try to make a voice recording using AVAudioRecorder

When I call AVAudioRecorder's "record" method in step 3, it returns NO indicating failure, but giving no hints as to why (come on Apple!) AVAudioRecorder's audioRecorderEncodeErrorDidOccur delegate method is never called and I receive no other errors when setting up the recorder.

My first guess was that the movie recording/playing was modifying the shared instance of "AVAudioSession" in such a way that it prevented the audio recorder from working. However, I'm manually setting AVAudioSession's category property to "AVAudioSessionCategoryRecord" and I make the audio session active before trying to record.

Here's my method for creating the recorder:

- (void)createAudioRecorder
{
 NSError *error = nil;
 AVAudioSession *audioSession = [AVAudioSession sharedInstance];
 [audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
 if (error)
  ...
 [audioSession setActive:YES error:&error];
 if (error)
  ...

 NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];

 // General Audio Format Settings 
 [settings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
 [settings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey]; 
 [settings setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];

 // Encoder Settings 
 [settings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey]; 
 [settings setValue:[NSNumber numberWithInt:96] forKey:AVEncoderBitRateKey]; 
 [settings setValue:[NSNumber numberWithInt:16] forKey:AVEncoderBitDepthHintKey];

 // Write the audio to a temporary file
 NSURL *tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"Recording.m4a"]];

 audioRecorder = [[AVAudioRecorder alloc] initWithURL:tempURL settings:settings error:&error];
 if (error)
  ...

 audioRecorder.delegate = self;
 if ([audioRecorder prepareToRecord] == NO)
  NSLog(@"Recorder fails to prepare!");

 [settings release];
}

And here's my method to start recording:

- (void)startRecording
{
 if (!audioRecorder)
  [self createAudioRecorder];

 NSError *error = nil;
 [[AVAudioSession sharedInstance] setActive:YES error:&error];
 if (error)
  ...

 BOOL recording = [audioRecorder record];
 if (!recording)
  NSLog(@"Recording won't start!");
}

Has anyone run into this problem before?

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

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

发布评论

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

评论(6

童话 2024-10-08 19:10:20

我也有同样的问题。在我解决这个问题之前,我的录音/播放代码是这样的:

开始录音功能

- (BOOL) startRecording {   
@try {
    NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey, [NSNumber numberWithFloat: 44100.0], AVSampleRateKey, [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,  [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey, nil];

        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:@"recording.caf"];

        if(audioRecorder != nil) {
            [audioRecorder stop];
            [audioRecorder release];
            audioRecorder = nil;
        }

        NSError *err = nil;
        audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:recordSetting error:&err];
        [soundFileURL release];
        [recordSetting release];
        if(!audioRecorder || err){
            NSLog(@"recorder initWithURL: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
            return NO;
        }

        [audioRecorder peakPowerForChannel:8];
        [audioRecorder updateMeters];
        audioRecorder.meteringEnabled = YES;
        [audioRecorder record];
    }
    @catch (NSException * e) {
        return NO;
    }

    recording = YES;
    return YES;
}

停止录音功能

- (BOOL) stopRecording {
    @try {
        [audioRecorder stop];
        [audioRecorder release];
        audioRecorder = nil;

        recording = NO;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

开始播放功能

- (BOOL) startPlaying {
    @try {
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:@"recording.caf"];      NSURL * soundFileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
        NSError *err = nil;

        if (audioPlayer) {
            [audioPlayer release];
            audioPlayer = nil;
        }

        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error: &err];
        [soundFileURL release];
        if (!audioPlayer || err) {
            NSLog(@"recorder: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
            return NO;
        }

        [audioPlayer prepareToPlay];
        [audioPlayer setDelegate: self];
        [audioPlayer play];

        playing = YES;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

停止播放功能

- (BOOL) stopPlaying {
    @try {
        [audioPlayer stop];
        [audioPlayer release];
        audioPlayer = nil;

        playing = NO;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

我修复了播放捕获视频后的录音问题,代码如下:

- (BOOL) startRecording {   
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryRecord error:nil];

        // rest of the recording code is the same .
}

- (BOOL) stopRecording {
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    // rest of the code is the same
}

- (BOOL) startPlaying {
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    // rest of the code is the same. 
}

- (BOOL) stopPlaying {
    // There is no change in this function
}

I was having the same issue. Before I fixed the issue, my recording/playback code was like this:

Start Recording Function

- (BOOL) startRecording {   
@try {
    NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey, [NSNumber numberWithFloat: 44100.0], AVSampleRateKey, [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,  [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey, nil];

        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:@"recording.caf"];

        if(audioRecorder != nil) {
            [audioRecorder stop];
            [audioRecorder release];
            audioRecorder = nil;
        }

        NSError *err = nil;
        audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:recordSetting error:&err];
        [soundFileURL release];
        [recordSetting release];
        if(!audioRecorder || err){
            NSLog(@"recorder initWithURL: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
            return NO;
        }

        [audioRecorder peakPowerForChannel:8];
        [audioRecorder updateMeters];
        audioRecorder.meteringEnabled = YES;
        [audioRecorder record];
    }
    @catch (NSException * e) {
        return NO;
    }

    recording = YES;
    return YES;
}

Stop Recording Function

- (BOOL) stopRecording {
    @try {
        [audioRecorder stop];
        [audioRecorder release];
        audioRecorder = nil;

        recording = NO;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

Start Playing Function

- (BOOL) startPlaying {
    @try {
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:@"recording.caf"];      NSURL * soundFileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
        NSError *err = nil;

        if (audioPlayer) {
            [audioPlayer release];
            audioPlayer = nil;
        }

        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error: &err];
        [soundFileURL release];
        if (!audioPlayer || err) {
            NSLog(@"recorder: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
            return NO;
        }

        [audioPlayer prepareToPlay];
        [audioPlayer setDelegate: self];
        [audioPlayer play];

        playing = YES;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

Stop Playing Function

- (BOOL) stopPlaying {
    @try {
        [audioPlayer stop];
        [audioPlayer release];
        audioPlayer = nil;

        playing = NO;
    }
    @catch (NSException * e) {
        return NO;
    }

    return YES;
}

I fixed the recording issue after playing a captured video, the code is as follows:

- (BOOL) startRecording {   
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryRecord error:nil];

        // rest of the recording code is the same .
}

- (BOOL) stopRecording {
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    // rest of the code is the same
}

- (BOOL) startPlaying {
    @try {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    // rest of the code is the same. 
}

- (BOOL) stopPlaying {
    // There is no change in this function
}
独享拥抱 2024-10-08 19:10:20

有同样的问题。我的解决方案是在开始录制会话之前停止电影。我的代码与 rmomin 的代码类似。

Had the same problem. My Solution was to STOP the movie before starting the recording session. My code was similar to rmomin's code.

緦唸λ蓇 2024-10-08 19:10:20

我也遇到了同样的问题。我使用 AVPlayer 来播放乐曲(之前的录音我使用过 AVAudioRecord)。然而,我发现一旦我使用了AVPlayer,我就无法再使用AVAudioRecorder了。经过一番搜索,我发现只要 AVPlayer 在内存中实例化并且至少播放过一次(通常是实例化后立即执行的操作),AVAudioRecorder 就不会录制。然而,一旦 AVPlayer 被释放,AVAudioRecorder 就可以再次自由录制。看来 AVPlayer 保留了 AVAudioRecorder 所需的某种连接,而且它很贪婪......它不会放开它,直到你从它冰冷的死手上撬开它。

这是我找到的解决方案。有些人声称实例化 AVPlayer 需要太多时间来不断崩溃和设置备份。然而,事实并非如此。实例化 AVPlayer 实际上非常简单。实例化 AVPlayerItem 也是如此。加载 AVAsset(或其任何子类)并不简单。你真的只想这样做一次。关键是使用这个序列:

  1. 加载 AVAsset(例如,如果您从文件加载,则直接使用 AVURLAsset 或将其添加到 AVMutableComposition 并使用它)并保留对它的引用。在完成之前不要放手。加载它总是需要时间。
  2. 准备好播放后:使用您的资源实例化 AVPlayerItem,然后使用 AVPlayerItem 实例化 AVPlayer 并播放它。不要保留对 AVPlayerItem 的引用,AVPlayer 将保留对它的引用,并且您无论如何都不能与其他播放器重用它。
  3. 一旦播放完毕,立即销毁 AVPlayer...释放它,将其 var 设置为 nil,无论您需要做什么。 **
  4. 现在您可以录制了。 AVPlayer 不存在,所以 AVAudioRecorder 可以自由地做它的事情。
  5. 当您准备好再次玩时,使用您已经加载的资源重新实例化 AVPlayerItem AVP 播放器。再说一遍,这是微不足道的。资产已经加载,因此不应有延迟。

** 请注意,销毁 AVPlayer 可能不仅仅需要释放它并将其 var 设置为 nil。最有可能的是,您还添加了一个周期性时间观察器来跟踪播放进度。当你这样做时,你会收到一个你应该抓住的不透明物体。如果您不从播放器中删除此项目并释放它/将其设置为 nil,AVPlayer 将不会释放。 Apple 似乎故意创建了一个必须手动打破的保留周期。因此,在销毁 AVPlayer 之前,您需要(示例):

[_player removeTimeObserver:_playerObserver];
[_playerObserver release]; //Only if you're not using ARC
 _playerObserver = nil;

作为旁注,您可能还设置了 NSNotifications(我使用一个来确定播放器何时完成播放)...也不要忘记删除它们。

I've been having the same problem. I use AVPlayer to play compositions (previous recordings I've used AVAudioRecord for). However, I found that once I've used AVPlayer I could no longer use AVAudioRecorder. After some searching, I discovered that so long as AVPlayer is instantiated in memory and has been played at least once (which is usually what you do immediately after instantiating it) AVAudioRecorder will not record. However, once AVPlayer is dealloc'd, AVAudioRecorder is then free to record again. It appears that AVPlayer holds on to some kind of connection that AVAudioRecorder needs, and it's greedy...it won't let it go until you pry it from it's cold dead hands.

This is the solution I've found. Some people claim that instantiating AVPlayer takes too much time to keep breaking down and setting back up. However, this is not true. Instantiating AVPlayer is actually quite trivial. So also is instantiating AVPlayerItem. What isn't trivial is loading up AVAsset (or any of it's subclasses). You really only want to do that once. They key is to use this sequence:

  1. Load up AVAsset (for example, if you're loading from a file, use AVURLAsset directly or add it to a AVMutableComposition and use that) and keep a reference to it. Don't let it go until you're done with it. Loading it is what takes all the time.
  2. Once you're ready to play: instantiate AVPlayerItem with your asset, then AVPlayer with the AVPlayerItem and play it. Don't keep a reference to AVPlayerItem, AVPlayer will keep a reference to it and you can't reuse it with another player anyway.
  3. Once it's done playing, immediately destroy AVPlayer...release it, set its var to nil, whatever you need to do. **
  4. Now you can record. AVPlayer doesn't exist, so AVAudioRecorder is free to do its thing.
  5. When you're ready to play again, re-instantiate AVPlayerItem with the asset you've already loaded & AVPlayer. Again, this is trivial. The asset has already been loaded so there shouldn't be a delay.

** Note that destroying AVPlayer may take more than just releasing it and setting its var to nil. Most likely, you've also added a periodic time observer to keep track of the play progress. When you do this, you receive back an opaque object you're supposed to hold on to. If you don't remove this item from the player AND release it/set it to nil, AVPlayer will not dealloc. It appears that Apple creates an intentional retain cycle you must break manually. So before you destroy AVPlayer you need to (example):

[_player removeTimeObserver:_playerObserver];
[_playerObserver release]; //Only if you're not using ARC
 _playerObserver = nil;

As a side note, you may also have set up NSNotifications (I use one to determine when the player has completed playing)...don't forget to remove those as well.

冰魂雪魄 2024-10-08 19:10:20

我在 Monotouch 中遇到了同样的问题,并调整了 Monotouch 的 rmomins 答案。

更改

avrecorder.Record();

NSError error;
var avsession = AVAudioSession.SharedInstance();
avsession.SetCategory(AVAudioSession.CategoryRecord,out error);

avrecorder.Record();

Works like a charm。

I had the same problem in Monotouch and adjusted rmomins answer for Monotouch.

changed

avrecorder.Record();

to

NSError error;
var avsession = AVAudioSession.SharedInstance();
avsession.SetCategory(AVAudioSession.CategoryRecord,out error);

avrecorder.Record();

Works like a charm.

落日海湾 2024-10-08 19:10:20

我在录制和播放时遇到了同样的问题。为了解决这个问题,我回顾了“录制”和“播放”功能中的 AVAudioSession 。

这可能对在设备上而不是在模拟器上遇到此问题的人有所帮助!

I had the same problem to record and play. To fix the problem I recall AVAudioSession in the "record" and "play" function.

This can may be help to person who has this problem on the device and not on the simulator!

仙女山的月亮 2024-10-08 19:10:20

我遇到了同样的问题。最后我发现ARC已经发布了我的录音机。因此,您必须在 .h 文件中声明录音机,即 AVAudioRecord *recorder;。将其他内容放入 .m 将正常工作。

I got the same problem. Finally I found out that ARC has released my recorder. So, you must declare the recorder in your .h file, i.e. AVAudioRecord *recorder;. Put other things to .m will work as normal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文