10

Mi aplicación de iPhone usa "AVAudioRecorder" para hacer grabaciones de voz. También usa "UIImagePickerController" para grabar películas y "MPMoviePlayerController" para reproducir películas.AVAudioRecorder no grabará SI la película fue grabada y reproducida previamente

Todo funciona bien hasta que lo haga las tres cosas consecutivas:

  1. grabar una película usando UIImagePickerController
  2. Reproduzca la película grabada usando MPMoviePlayerController
  3. tratar de hacer una grabación de voz usando AVAudioRecorder

Cuando llamo al método "grabar" de AVAudioRecorder en el paso 3, devuelve NO indicando el error, pero sin dar pistas de por qué (vaya a Appl e!) El método de delegado audioRecorderEncodeErrorDidOccur de AVAudioRecorder nunca se llama y no recibo ningún otro error al configurar la grabadora.

Mi primera suposición fue que la grabación/reproducción de películas estaba modificando la instancia compartida de "AVAudioSession" de tal forma que impedía que la grabadora de audio funcionara. Sin embargo, estoy configurando manualmente la propiedad de categoría de AVAudioSession en "AVAudioSessionCategoryRecord" y activo la sesión de audio antes de intentar grabar.

Aquí es mi método para crear la grabadora:

- (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]; 
} 

y aquí está mi método para iniciar la grabación:

- (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!"); 
} 

Cualquier persona ha funcionado en este problema antes?

Respuesta

14

Estaba teniendo el mismo problema. Antes de que me ha solucionado el problema, mi código de grabación/reproducción era así:

Función

Iniciar grabación Función

- (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; 
} 

Detener grabación

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

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

    return YES; 
} 

Comienza a Jugar Función

- (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; 
} 

dejar de jugar Función

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

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

    return YES; 
} 

me ha solucionado el problema de grabación después de la reproducción de un vídeo capturado, el código es el siguiente:

- (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 
} 
+0

¡Gracias, estaba teniendo el mismo problema y no podía entender lo que estaba mal por mucho tiempo! –

+0

Gracias, ayudó. –

0

que tenían el mismo problema en MonoTouch y se ajusta rmomins respuesta para Monotouch.

cambió

avrecorder.Record(); 

a

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

avrecorder.Record(); 

funciona como un encanto.

1

He estado teniendo el mismo problema. Uso AVPlayer para reproducir composiciones (grabaciones anteriores para las que utilicé AVAudioRecord). Sin embargo, descubrí que una vez que he usado AVPlayer ya no puedo usar AVAudioRecorder. Después de algunas búsquedas, descubrí que siempre que AVPlayer se haya instanciado en la memoria y se haya reproducido al menos una vez (lo cual es usualmente lo que se hace inmediatamente después de crear una instancia) AVAudioRecorder no grabará. Sin embargo, una vez que AVPlayer se desasigna, AVAudioRecorder quedará libre para grabar nuevamente. Parece que AVPlayer se aferra a algún tipo de conexión que AVAudioRecorder necesita, y es codicioso ... no lo dejará ir hasta que lo saques de sus frías manos muertas.

Esta es la solución que he encontrado. Algunas personas afirman que la creación de instancias de AVPlayer toma demasiado tiempo para seguir desglosando y configurando una copia de seguridad. Sin embargo, eso no es verdad. La creación de instancias de AVPlayer es bastante trivial. Así que también está creando instancias de AVPlayerItem. Lo que no es trivial está cargando AVAsset (o cualquiera de sus subclases). Realmente solo quieres hacer eso una vez. clave que es utilizar esta secuencia:

  1. carga hasta AVAsset (por ejemplo, si va a cargar desde un archivo, utilice AVURLAsset directa o añadirlo a una AVMutableComposition y usar eso) y tener una referencia a él. No lo dejes ir hasta que hayas terminado con eso. Cargarlo es lo que lleva todo el tiempo.
  2. Una vez que esté listo para jugar: cree una instancia de AVPlayerItem con su activo, luego AVPlayer con AVPlayerItem y juegue. No mantenga una referencia a AVPlayerItem, AVPlayer lo mantendrá referenciado y no podrá reutilizarlo con otro reproductor de todos modos.
  3. Una vez que haya terminado de jugar, destruye inmediatamente AVPlayer ... libéralo, establece su var a nil, lo que sea que necesites hacer. **
  4. Ahora puede grabar. AVPlayer no existe, por lo que AVAudioRecorder es libre de hacer su trabajo.
  5. Cuando esté listo para volver a jugar, vuelva a crear una instancia de AVPlayerItem con el activo que ya ha cargado & AVPlayer. Nuevamente, esto es trivial. El activo ya se ha cargado, por lo que no debería haber un retraso.

** Tenga en cuenta que la destrucción de AVPlayer puede requerir algo más que simplemente liberarla y establecer su var en cero. Lo más probable es que también haya agregado un observador de tiempo periódico para realizar un seguimiento del progreso de la reproducción. Cuando haces esto, recibes de vuelta un objeto opaco al que debes aferrarte. Si no quita este elemento del reproductor Y lo suelta/establece en cero, AVPlayer no se destrabará. Parece que Apple crea un ciclo de retención intencional que debe romper manualmente. Así que antes de destruir AVPlayer lo que necesita (ejemplo):

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

Como nota al margen, es posible que también haya configurado NSNotifications (utilizo uno para determinar cuando el jugador ha completado de juego) no lo hace ... olvida eliminar esos también.

2

Tenía el mismo problema. Mi solución fue DETENER la película antes de comenzar la sesión de grabación. Mi código era similar al código de romomin.

0

Tuve el mismo problema para grabar y jugar.Para solucionar el problema, recuerdo AVAudioSession en la función "grabar" y "reproducir".

¡Esto puede ayudar a la persona que tiene este problema en el dispositivo y no en el simulador!

0

Tengo el mismo problema. Finalmente descubrí que ARC ha lanzado mi grabadora. Por lo tanto, debe declarar el grabador en su archivo .h, es decir, AVAudioRecord *recorder;. Ponga otras cosas a .m funcionará normalmente.

Cuestiones relacionadas