从 AVAudioRecorder 播放后 AVAudioPlayer 崩溃
我有一个按钮,用户点击即可开始录制,再次点击即可停止。当它停止时,我希望录制的声音“回声”回来,以便用户可以听到录制的内容。第一次这个效果很好。如果我第三次点击该按钮,它会开始新的录制,当我点击停止时,它会崩溃并显示 EXC_BAD_ACCESS。
- (IBAction) readToMeTapped {
if(recording)
{
recording = NO;
[readToMeButton setTitle:@"Stop Recording" forState: UIControlStateNormal ];
NSMutableDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
// Create a new dated file
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
recordedTmpFile = [NSURL fileURLWithPath:[[NSString stringWithFormat:@"%@/%@.caf", DOCUMENTS_FOLDER, caldate] retain]];
error = nil;
recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];
[recordSetting release];
if(!recorder){
NSLog(@"recorder: %@ %d %@", [error domain], [error code], [[error userInfo] description]);
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle: @"Warning"
message: [error localizedDescription]
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
NSLog(@"Using File called: %@",recordedTmpFile);
//Setup the recorder to use this file and record to it.
[recorder setDelegate:self];
[recorder prepareToRecord];
[recorder recordForDuration:(NSTimeInterval) 5]; //recording for a limited time
}
else
{ // it crashes the second time it gets here!
recording = YES;
NSLog(@"Recording YES Using File called: %@",recordedTmpFile);
[readToMeButton setTitle:@"Start Recording" forState:UIControlStateNormal ];
[recorder stop]; //Stop the recorder.
//playback recording
AVAudioPlayer * newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error];
[recordedTmpFile release];
self.aPlayer = newPlayer;
[newPlayer release];
[aPlayer setDelegate:self];
[aPlayer prepareToPlay];
[aPlayer play];
}
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)sender successfully:(BOOL)flag {
NSLog (@"audioRecorderDidFinishRecording:successfully:");
[recorder release];
recorder = nil;
}
检查调试器,它在这里标记错误
@synthesize aPlayer, recorder;
这是我不明白的部分。我认为这可能与释放内存有关,但我一直很小心。我错过了什么吗?
I've got a button the user tap to start recording and tap again to stop. When it stop I want the recorded voice 'echo' back so the user can hear what was recorded. This works fine the first time. If I hit the button for the third time, it starts a new recording and when I hit stop it crashes with EXC_BAD_ACCESS.
- (IBAction) readToMeTapped {
if(recording)
{
recording = NO;
[readToMeButton setTitle:@"Stop Recording" forState: UIControlStateNormal ];
NSMutableDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
// Create a new dated file
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
recordedTmpFile = [NSURL fileURLWithPath:[[NSString stringWithFormat:@"%@/%@.caf", DOCUMENTS_FOLDER, caldate] retain]];
error = nil;
recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];
[recordSetting release];
if(!recorder){
NSLog(@"recorder: %@ %d %@", [error domain], [error code], [[error userInfo] description]);
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle: @"Warning"
message: [error localizedDescription]
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
NSLog(@"Using File called: %@",recordedTmpFile);
//Setup the recorder to use this file and record to it.
[recorder setDelegate:self];
[recorder prepareToRecord];
[recorder recordForDuration:(NSTimeInterval) 5]; //recording for a limited time
}
else
{ // it crashes the second time it gets here!
recording = YES;
NSLog(@"Recording YES Using File called: %@",recordedTmpFile);
[readToMeButton setTitle:@"Start Recording" forState:UIControlStateNormal ];
[recorder stop]; //Stop the recorder.
//playback recording
AVAudioPlayer * newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error];
[recordedTmpFile release];
self.aPlayer = newPlayer;
[newPlayer release];
[aPlayer setDelegate:self];
[aPlayer prepareToPlay];
[aPlayer play];
}
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)sender successfully:(BOOL)flag {
NSLog (@"audioRecorderDidFinishRecording:successfully:");
[recorder release];
recorder = nil;
}
Checking the debugger, it flags the error here
@synthesize aPlayer, recorder;
This is the part I don't understand. I thought it may have something to do with releasing memory but I've been careful. Have I missed something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
经过一段时间的研究后,我偶然发现了这个调试技巧。它显示 AVAudioPlayer 第二次被释放,导致崩溃。那么代表一定已经完成了清理工作吗?我检查了这个 SO 线程,它是建议代表不要取消分配。但是,如果我删除该行
“我的程序可以运行”!阅读此 SO 线程后,我相信我的问题是我应该实现 AVAudioPlayerDelegate 的 - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player success:(BOOL)flag 方法并在声音播放完毕后释放音频播放器。我是为 AVAudioRecorder 做的。
After working on it for a while I stumbled on this debugging tip. It showed me that AVAudioPlayer was deallocated the second time around, causing the crash. So the Delegate must have done the clean up? I checked this SO thread and it is suggestion that the Delegate does not deallocate. However, if I remove the line
My program works! After reading this SO thread, I believe my issue is that I should implement
AVAudioPlayerDelegate's - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
method and release the audio player there, after the sound is done playing. I had done it for AVAudioRecorder.您是否确保
@property (retain)
不包含非原子?我认为访问这些属性的某些代码可能是从另一个线程执行的。另外,您应该始终使用 self.recorder 和 self.player 通过其 getter 来访问这些属性,以确保在各自的锁内访问它们。Did you make sure that
@property (retain)
does not include nonatomic? I'm thinking that some of the code that accesses those properties may be doing so from another thread. Also, you should always access those properties via their getters by using self.recorder and self.player, in order to make sure they are accessed within their respective locks.