AVAudioRecorder не будет записывать, если фильм был ранее записан и воспроизведен - PullRequest
10 голосов
/ 10 ноября 2010

Приложение для iPhone использует «AVAudioRecorder» для записи голоса. Он также использует «UIImagePickerController» для записи фильмов и «MPMoviePlayerController» для воспроизведения фильмов.

Все работает нормально, пока я не сделаю все три вещи подряд:

  1. Запись фильма с использованием UIImagePickerController
  2. Воспроизведение записанного фильма с помощью MPMoviePlayerController
  3. Попробуйте сделать запись голоса с помощью AVAudioRecorder

Когда я вызываю метод «записи» AVAudioRecorder на шаге 3, он возвращает НЕТ, указывающий на ошибку, но не дает подсказок о том, почему (давай, Apple!) Метод делегата audioRecorderEncodeErrorDidOccur AVAudioRecorder никогда не вызывается, и я не получаю других ошибок при настройке рекордер.

Моим первым предположением было, что при записи / воспроизведении фильма модифицируется общий экземпляр «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!");
}

Кто-нибудь сталкивался с этой проблемой раньше?

Ответы [ 6 ]

14 голосов
/ 22 апреля 2011

У меня была такая же проблема. До того, как я исправил проблему, мой код записи / воспроизведения был таким:

Функция начала записи

- (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
}
2 голосов
/ 18 июля 2012

Была такая же проблема. Мое решение состояло в том, чтобы остановить фильм перед началом сеанса записи. Мой код был похож на код rmomin.

1 голос
/ 03 мая 2012

У меня была такая же проблема.Я использую AVPlayer для воспроизведения композиций (предыдущие записи, для которых я использовал AVAudioRecord).Тем не менее, я обнаружил, что, когда я использовал AVPlayer, я больше не мог использовать AVAudioRecorder.После некоторых поисков я обнаружил, что до тех пор, пока AVPlayer создается в памяти и воспроизводится хотя бы один раз (что обычно и делается сразу после его создания), AVAudioRecorder не будет записывать.Однако, как только AVPlayer будет освобожден, AVAudioRecorder снова будет свободен для записи.Похоже, что AVPlayer поддерживает какое-то соединение, которое нужно AVAudioRecorder, и оно жадное ... оно не пропустит его, пока вы не вырвете его из холодных мертвых рук.

Это решение, которое я 'нашел.Некоторые люди утверждают, что создание экземпляра AVPlayer занимает слишком много времени, чтобы продолжать ломаться и восстанавливать настройки.Однако это не так.Создание AVPlayer на самом деле довольно тривиально.Так же является создание экземпляра AVPlayerItem.То, что не тривиально, это загрузка AVAsset (или любого из его подклассов).Вы действительно хотите сделать это только один раз.Они должны использовать эту последовательность:

  1. Загрузите AVAsset (например, если вы загружаете из файла, используйте AVURLAsset напрямую или добавьте его в AVMutableComposition и используйте его) и сохраните ссылкук этому.Не отпускай, пока не покончишь с этим.Загрузка - это то, что занимает все время.
  2. Как только вы будете готовы к игре: создайте экземпляр AVPlayerItem с вашим активом, затем AVPlayer с AVPlayerItem и воспроизведите его.Не сохраняйте ссылку на AVPlayerItem, AVPlayer сохранит ссылку на нее, и вы все равно не сможете повторно использовать ее с другим игроком.
  3. Как только игра закончится, немедленно уничтожит AVPlayer ... отпустите его, установите его переменную на ноль, что вам нужно сделать.**
  4. Теперь вы можете записывать.AVPlayer не существует, поэтому AVAudioRecorder может делать свое дело.
  5. Когда вы будете готовы снова играть, создайте экземпляр AVPlayerItem с активом, который вы уже загрузили, и AVPlayer.Опять же, это тривиально.Актив уже загружен, поэтому задержка не должна быть.

** Обратите внимание, что уничтожение AVPlayer может занять больше, чем просто его освобождение и установка его переменной равной nil.Скорее всего, вы также добавили периодического наблюдателя времени, чтобы отслеживать ход игры.Когда вы делаете это, вы получаете обратно непрозрачный объект, который вы должны удерживать.Если вы не удалите этот элемент из плеера и не отпустите его / не установите ноль, AVPlayer не будет освобожден.Похоже, что Apple создает намеренный цикл хранения, который вы должны прервать вручную.Поэтому перед тем, как уничтожить AVPlayer, вам необходимо (пример):

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

В качестве дополнительной заметки вы, возможно, также настроили NSNotifications (я использую его, чтобы определить, когда игрок завершил игру) ...не забудьте также удалить их.

0 голосов
/ 05 апреля 2013

У меня такая же проблема. Наконец я узнал, что ARC выпустил мой рекордер. Итак, вы должны объявить рекордер в вашем .h файле, т.е. AVAudioRecord *recorder;. Положите другие вещи в .m будет работать как обычно.

0 голосов
/ 28 января 2013

У меня была та же проблема с записью и воспроизведением.Чтобы исправить проблему, я вспоминаю AVAudioSession в функциях «запись» и «воспроизведение».

Это может помочь человеку, который имеет эту проблему на устройстве, а не на симуляторе!

0 голосов
/ 27 февраля 2012

У меня была такая же проблема в Monotouch и настроен rmomins ответ для Monotouch.

изменено

avrecorder.Record();

на

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

avrecorder.Record();

Работает как шарм.

...