AVAudioRecorder теряет последние секунды

Я использую AVAudioRecorder для записи аудиофайла различной длины со следующей конфигурацией:

- (AVAudioRecorder*)recorder
{
    if(!_recorder) {
        // Set the audio file
        NSArray *pathComponents = [NSArray arrayWithObjects:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"ExamTranscript.m4a", nil];
        self.soundFileURL = [NSURL fileURLWithPathComponents:pathComponents];

        // Define the recorder setting
        NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];

        [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
        [recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey];
        [recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];

        // Initiate and prepare the recorder
        _recorder = [[AVAudioRecorder alloc] initWithURL:self.soundFileURL settings:recordSetting error:NULL];
        _recorder.meteringEnabled = YES;
        _recorder.delegate = self;
    }

    return _recorder;
}

Когда я вызываю [self.recorder stop], последние 2-3 секунды записи никогда не записываются (и они определенно необходимы).

Например, если я позвоню self.recorder.currentTime прямо перед вызовом [self.recorder stop], я получу NSTimeInterval, превышающий фактическую продолжительность сгенерированного файла примерно на 2-3 секунды. Все, что было записано за эти 2-3 секунды, теряется.

После вызова [self.recorder stop] я получаю вызов соответствующего audioRecorderDidFinishRecording:successfully: метода делегата, и флаг указывает на его успешное выполнение.

Я совершенно не понимаю, как теряются эти последние секунды. (Рекордер не выпускается, и до сих пор на него есть сильная ссылка.)

ОБНОВЛЕНИЕ

Приложение несколько раз предлагает пользователю говорить, поэтому AVAudioRecorder приостанавливается и возобновляет работу несколько раз, прежде чем будет остановлен в конце окончательного ответа. Он приостанавливается, а не останавливается, потому что все это необходимо записать в один аудиофайл.


person TimOfTheYear    schedule 16.12.2013    source источник


Ответы (1)


Глядя на ограниченный код, которым вы поделились, я могу только подозревать, что вы могли неправильно использовать объект записи.

Ключевые моменты ниже и дополнительный код, который может вам помочь ... (у меня это работает)

1) Вам следует создавать / запускать AVAudioRecorder каждый раз, когда вы начинаете новую запись.

2) свойство currentTime AVAudioRecorder действительно только во время записи (т.е. isRecording имеет значение YES).

// class properties
@property (nonatomic, retain) AVAudioRecorder *audioRecorder;
@property (nonatomic, retain) NSDictionary *recordQualitySettings;
@property (nonatomic, assign) NSInteger maxRecordDurationInSeconds;

// class's designated initializer
- (instancetype)init
{
    self = [super init];

    if (self) {
        self.recordQualitySettings = [NSDictionary
                               dictionaryWithObjectsAndKeys:
                               [NSNumber numberWithInt:kAudioFormatAppleIMA4],
                               AVFormatIDKey,
                               [NSNumber numberWithInt:1],
                               AVNumberOfChannelsKey,
                               [NSNumber numberWithFloat:16000.0],  //??
                               AVSampleRateKey,
                               nil];
...
...
    }

    return self;
}

- (void)recordBegin
{
    NSString *temnpVoiceFile = [NSString pathWithComponents:[NSArray arrayWithObjects:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"tempVoice.caf", nil]];
    NSURL *soundFileURL = [NSURL fileURLWithPath:temnpVoiceFile];
    NSError *error = nil;

    // Instantiate an audio recorder.
    self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:self.recordQualitySettings error:&error];
    NSAssert1(!error, @"error creating audio file = %@", error);

    self.audioRecorder.delegate = self;
    self.audioRecorder.meteringEnabled = YES;

    [self.audioRecorder recordForDuration:self.maxRecordDurationInSeconds];   // Any of the 'record..' methods that triggers recording.

}

РЕДАКТИРОВАТЬ:

После записи вашего звонка stop с использованием [self.audioRecorder stop] или внутри audioRecorderDidFinishRecording метода делегата проверьте продолжительность звука с помощью приведенного ниже кода (на основе URL-адреса)? Просто чтобы проверить, что currentTime неверно.

AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:self.audioRecorder.url options:nil];   // delegate method provide you `recorder` object as parameter too.
CMTime audioDuration = audioAsset.duration;
double duration = CMTimeGetSeconds(audioDuration);
person Ashok    schedule 16.12.2013
comment
Я делаю только одну запись, поэтому я не пытаюсь использовать один и тот же экземпляр AVAudioRecorder для создания нескольких записей. Кроме того, доступ к recorder.currentTime осуществляется только внутри условного if(recorder.isRecording). - person TimOfTheYear; 17.12.2013
comment
Чтобы помочь вам лучше, предоставьте дополнительный код в контексте. Как вы записываете / приостанавливаете / останавливаете диктофон и где вы проверяете currentTime? Если stop выполняется в основном потоке (isMainThread) и т. Д. Также обратите внимание на ИЗМЕНИТЬ в моем ответе выше. - person Ashok; 17.12.2013