ios - quitar - programa para eliminar ruidos de grabaciones de audio
El audio de fondo no se reanuda después de una llamada (6)
Mi audio de fondo funciona bien casi todo el tiempo. Pantalla bloqueada, o silencio de encendido. Pero cuando el usuario tiene la aplicación en segundo plano y recibe una llamada, incluso si el usuario no responde la llamada, el audio de fondo no se reanuda después de que finaliza la interrupción.
La aplicación de Música reanuda correctamente el audio de fondo si se interrumpió.
¿Falta alguna propiedad o necesito una devolución de llamada o configurar una tarea en segundo plano para continuar la ejecución de audio en segundo plano después de una interrupción? ¿O esto es algo que no podemos hacer?
En mi experiencia, descubrí que tenía que "esperar uno o dos segundos" antes de volver a abrir el dispositivo de audio. Creo que después de que el sistema operativo cambie de nuevo a su aplicación después de la llamada, la aplicación del teléfono todavía se está cerrando.
algo como esto cuando regresa a primer plano después de saber que su sesión de audio se ha detenido:
dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW,
1.5LL * NSEC_PER_SEC);
dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{
[audioSystem restart];
});
Estamos reanudando nuestro audio después de una llamada saliente y una llamada entrante mientras la aplicación está en segundo plano.
Reproducimos audio con AVAudioPlayer y escuchamos AVAudioSessionInterruptionNotification . Apple detiene automáticamente el AVAudioPlayer en caso de que se produzca una interrupción y, cuando le indica que se reanude después de recibir la interrupción, Apple volverá a activar su sesión. Consulte la Tabla 3-2 de Manejo de interrupciones de audio para obtener recomendaciones si está utilizando otros tipos de tecnologías de audio.
Suscríbete a la notificación:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];
Manejar la notificación:
- (void) onAudioSessionEvent: (NSNotification *) notification
{
//Check the type of notification, especially if you are sending multiple AVAudioSession events here
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
NSLog(@"Interruption notification received!");
//Check to see if it was a Begin interruption
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
NSLog(@"Interruption began!");
} else {
NSLog(@"Interruption ended!");
//Resume your audio
}
}
}
Estoy usando Xamarin, así que esto es C # pero el siguiente código funciona para mí. Primero establecí que mi AppDelegate implementa los métodos de delegado AVAudioSession incluyendo IAVAudioSessionDelegate
public partial class AppDelegate: UIApplicationDelegate, IAVAudioSessionDelegate
Agregué una variable a la clase AppDelegate para la sesión de audio
public static AVAudioSession AudioSession;
En la anulación del método FinishedLaunching:
AudioSession = AVAudioSession.SharedInstance();
AudioSession.Delegate = this;
error = AudioSession.SetCategory( AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers );
AudioSession.SetMode( new NSString( "AVAudioSessionModeMoviePlayback" ), out error );
Los dos métodos de delegado relevantes en AppDelegate.cs son:
[Export( "beginInterruption" )]
public void BeginInterruption()
{
PlayerViewController.BeginSessionInterruption();
}
[Export( "endInterruptionWithFlags:" )]
public void EndInterruption( AVAudioSessionInterruptionFlags flags )
{ // ignore the flags so we''re not dependent on the interrupting event saying that we can resume
PlayerViewController.ResumeAfterSessionInterruption();
}
My AppDelegate también tiene una anulación de OnActivated para habilitar las pistas de video si es un activo de video, y una anulación de DidEnterBackground para deshabilitar las pistas de video de los medios, pero aún así reproducir el audio.
En el método PlayerViewController.BeginSessionInterruption (), no puedo mirar Player.Rate para ver si el jugador se estaba ejecutando en ese momento, porque la alarma de interrupción o la llamada telefónica ya han detenido el reproductor. De la sección "Respuesta a interrupciones" de la Guía de programación de sesiones de audio de Apple, con mi énfasis agregado:
- Tu aplicación está activa, reproduciendo audio.
- Llega una llamada telefónica. El sistema activa la sesión de audio de la aplicación del teléfono.
- El sistema desactiva su sesión de audio. En este punto, * la reproducción en tu aplicación se ha detenido * .
- El sistema invoca la función de devolución de llamada del oyente de interrupción que indica que su sesión se ha desactivado. ...
El botón Reproducir de Mi PlayerViewController tiene una propiedad Pausada para alternar entre Reproducir y Pausar y dibujar la imagen del botón correspondiente. Así que en lugar de verificar Player.Rate, miro para ver si la propiedad Pausada del botón es falsa:
public void BeginSessionInterruption()
{
PlayerWasRunningOnInterruption = !btnPlay.Paused;
TogglePlayPause( true ); // put the Play button into the Paused state to agree with the player being stopped
}
public void ResumeAfterSessionInterruption()
{
NSError error;
AppDelegate.AudioSession.SetActive( true, AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation, out error ); // always reactivate the audio session
if ( PlayerWasRunningOnInterruption )
{
// rewind a little bit
// call btnPlayClick to resume the playback as if the user pressed the Play button
}
}
Mirar:
Código:
private func setupAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
try AVAudioSession.sharedInstance().setActive(true)
setupAudioNotifications()
} catch {
print(error)
}
}
private func setupAudioNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: .AVAudioSessionInterruption, object: nil)
}
@objc func handleInterruption(notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
return
}
if type == .began {
// Interruption began, take appropriate actions
Player.shared.stop()
} else if type == .ended {
if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
// Interruption Ended - playback should resume
Player.shared.start()
} else {
// Interruption Ended - playback should NOT resume
}
}
}
}
Sólo dos opciones funcionan para mí:
volver a cargar
AVPlayer
oAVAudioPlayer
después de que finalice la interrupciónfunc interruptionNotification(_ notification: Notification) { guard let type = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt, let interruption = AVAudioSessionInterruptionType(rawValue: type) else { return } if interruption == .ended && playerWasPlayingBeforeInterruption { player.replaceCurrentItem(with: AVPlayerItem(url: radioStation.url)) play() }
}
utilizar
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
Si solo detecta el estado de la llamada, puede usar CTCallCenter , pero si desea detectar la interrupción (incluir la interrupción de la llamada), puede usar AVAudioSessionInterruptionNotification , y si desea respaldar el fondo, debe agregar un código como este:
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
Antes de reanudar la reproducción de música en segundo plano. Espero que esto pueda ayudar.