AVAudioPlayerNode возвращается с обработчиком слишком рано

Я хотел бы воспроизвести звук перед записью звука. Я играю звук с AVAudioPlayerNode, затем в обработчике завершения я начинаю запись. Моя проблема в том, что обработчик завершения запускается примерно за 0,45 секунды до того, как фактически закончится воспроизведение звука. Это потому, что я записываю 0,45 секунды звука в начале записи. Вместо этого я хотел бы начать запись именно тогда, когда закончится воспроизведение звука. Вот мой код:

@interface ViewController ()

@property (strong, nonatomic) NSMutableDictionary *recordingSettings;
@property (strong, nonatomic) AVAudioRecorder *audioRecorder;
@property (nonatomic, strong) AVAudioEngine *engine;
@property (nonatomic, strong) AVAudioPlayerNode *audioPlayerNode;
@property (nonatomic, strong) AVAudioFile *audioFile;
@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error: nil];

    self.engine = [AVAudioEngine new];
    self.audioPlayerNode = [AVAudioPlayerNode new];

    [self.engine attachNode:self.audioPlayerNode];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Sound.wav" ofType:nil];
    self.audioFile = [[AVAudioFile alloc] initForReading:[NSURL fileURLWithPath:path]
                                                   error:nil];

    AVAudioMixerNode *mixerNode = [self.engine mainMixerNode];
    [self.engine connect:self.audioPlayerNode
                      to:mixerNode
                  format:self.audioFile.processingFormat];

    NSError *error;
    [self.engine startAndReturnError:&error];
    if (error) {
        NSLog(@"error:%@", error);
    }

    [self.audioPlayerNode play];
}


- (IBAction)record:(id)sender {
    [self.audioPlayerNode scheduleFile:self.audioFile
                                atTime:nil
                     completionHandler:^{
                         NSArray *pathComponents = [NSArray arrayWithObjects:
                                                    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
                                                    [NSString stringWithFormat:@"%@.m4a", @"testsound"],
                                                    nil];

                         NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];

                         self.recordingSettings = [[NSMutableDictionary alloc] init];
                         [self.recordingSettings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
                         [self.recordingSettings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
                         [self.recordingSettings setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];

                         NSError* error;
                         self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:self.recordingSettings error:&error];
                         if (error != nil) {
                             NSLog(@"RecordError: %@", error.localizedDescription);
                         }
                         self.audioRecorder.delegate = self;
                         self.audioRecorder.meteringEnabled = YES;
                         [self.audioRecorder prepareToRecord];

                         [self.audioRecorder record];

                     }];
}

- (IBAction)stopRecording:(id)sender {
    [self.audioRecorder stop];
}

- (IBAction)play:(id)sender {

    NSArray *pathComponents = [NSArray arrayWithObjects:
                               [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
                               [NSString stringWithFormat:@"%@.m4a", @"testsound"],
                               nil];

    NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
    NSLog(@"%@",outputFileURL.absoluteString);

    NSError* error;
    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:outputFileURL error:&error];


    if (error != nil) {
        NSLog(@"PlayError: %@", error.localizedDescription);
    }
    [self.audioPlayer setDelegate:self];
    [self.audioPlayer prepareToPlay];
    [self.audioPlayer play];
}

@end

В качестве обходного пути я откладываю запись на 0,45 секунды следующим образом:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.45 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
                             [self.audioRecorder record];
                         });

Скажите, пожалуйста, почему обработчик завершения вызывается до полного воспроизведения звука или есть лучший способ записи сразу после завершения воспроизведения звука?

0 ответов

Другие вопросы по тегам