Volumen inferior de iPod para reproducir el sonido de la aplicación (como la aplicación de SMS nativa)

Hice una aplicación de iPhone para usar durante el ejercicio. Reproduce un tono de campana para indicar que usted (el usuario) debe cambiar de un paso de su rutina de ejercicios a la siguiente. Diseñé la aplicación para que puedas escuchar música en el iPod mientras uso la aplicación, y quiero que el tono se reproduzca de forma suficientemente audible sobre la música. He conseguido que esto funcione … algo así como …

Cuando la música es alta, es difícil escuchar el tono. Mi solución ideal es algo similar a la forma en que la aplicación iPod maneja un post de text o correo electrónico entrante. El volumen de la música disminuye, el sonido se reproduce, luego el volumen de la música vuelve a fundirse.

Aquí están los enfoques que he intentado hasta ahora:

  1. He usado AudioServicesPlaySystemSound para reproducir el sonido.

    Inicié el sonido de esta manera:

     CFBundleRef mainBundle = CFBundleGetMainBundle(); soundFileURLRef = CFBundleCopyResourceURL(mainBundle, CFSTR ("bell"), CFSTR ("wav"), NULL); AudioServicesCreateSystemSoundID (soundFileURLRef, &soundFileID); 

    Y toco el sonido en el momento apropiado usando:

     AudioServicesPlaySystemSound (self.soundFileID); 

    Esto reproduce el sonido bien, pero es demasiado difícil escuchar la música a todo volumen. Encendido para intentar 2 …

  2. Intenté bajar el volumen del iPod, reproducir el sonido y luego devolver el volumen a su nivel anterior.

    Si queda 1 segundo en el paso actual, comience a bajar el volumen:

     if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) { self.volumeIncrement = originalVolume/5.0f; [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(fadeVolumeOut:) userInfo:[NSNumber numberWithInt:1] repeats:NO]; } 

    Aquí está el método fadeVolumeOut: :

     - (void) fadeVolumeOut:(NSTimer *)timer { if (!TARGET_IPHONE_SIMULATOR) { NSNumber *volumeStep = (NSNumber *)[timer userInfo]; int vStep = [(NSNumber *)volumeStep intValue]; float volume = [[MPMusicPlayerController iPodMusicPlayer] volume]; volume = volume - self.volumeIncrement; if (volume < 0.0f) { volume = 0.0f; } [[MPMusicPlayerController iPodMusicPlayer] setVolume:volume]; if (vStep < 5) { vStep = vStep + 1; [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(fadeVolumeOut:) userInfo:[NSNumber numberWithInt:vStep] repeats:NO]; } } } 

    Luego, cuando finalice el paso, reproduzca el sonido de alerta y vuelva a volcar el volumen en:

      [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(alertAndFadeVolumeIn) userInfo:nil repeats:NO]; 

    Aquí está el método alertAndFadeVolumeIn :

      - (void) alertAndFadeVolumeIn { [self alert]; [NSTimer scheduledTimerWithTimeInterval:0.25f target:self selector:@selector(fadeVolumeIn:) userInfo:[NSNumber numberWithInt:1] repeats:NO]; } 

    Y fadeVolumeIn: es básicamente lo opuesto a fadeVolumeOut: arriba.

    Esto funciona, el volumen se desvanece, el sonido se reproduce y el volumen vuelve a desaparecer. El problema es que el volumen del tono se networkinguce en la misma cantidad que el iPod, por lo que no es más fácil escuchar la música .

  3. AVAudioSession a AVAudioSession para reproducir el sonido y configuré la session para que la música del iPod continúe reproduciéndose mientras la aplicación esté en uso. Así es como inicializo la session:

      AVAudioSession *session = [AVAudioSession shanetworkingInstance]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; OSStatus propertySetError = 0; UInt32 allowMixing = true; propertySetError = AudioSessionSetProperty ( kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), &allowMixing ); NSError *activationError = nil; [session setActive:YES error:&activationError]; NSString *audioFile = [[NSBundle mainBundle] pathForResource:@"bell" ofType:@"wav"]; player = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:audioFile] error:NULL]; 

    Para reproducir el sonido, [self.player play] en el momento apropiado. Nuevamente, el volumen del tono disminuye junto con el volumen del iPod, y el tono no es más fácil de escuchar.

  4. Intenté poner [[MPMusicPlayerController applicationMusicPlayer] setVolume:1.0f]; justo antes de que se escuche el sonido de alerta. Esto tuvo resultados mixtos. La primera vez que el sonido se reproduce a volumen completo como lo esperaba, pero el volumen posterior es mucho menor. Además, la música no se desvanece fácilmente. Parece que iPodMusicPlayer y applicationMusicPlayer comparten el mismo volumen. ¿Esto es el resultado de usar [AVAudioSession shanetworkingInstance]; ? ¿Hay otra forma de inicializar una AVAudioSession ?

  5. A continuación, intenté usar AVAudioSession "ducking":

      OSStatus propertySetError = 0; UInt32 allowDucking = true; propertySetError = AudioSessionSetProperty ( kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof (allowDucking), &allowDucking ); 

    Desafortunadamente, la música del iPod "se pica" cuando se activa la session de audio, que es tan pronto como viewController se carga de la manera en que tenía las cosas.

  6. Finalmente, cambié mi código para que la session de audio se active un segundo antes de que termine el paso, el sonido se reproduce cuando termina el paso y, un segundo más tarde, la session se desactiva. He eliminado todo mi código de desvanecimiento de input y salida en este momento. Estos son los fragments de código relevantes:

     if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) { AVAudioSession *session = [AVAudioSession shanetworkingInstance]; [session setActive:YES error:nil]; } 

     if (self.shouldRing) { [self.player play]; [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(stopSound) userInfo:nil repeats:NO]; } 

     - (void) stopSound { [self.player stop]; AVAudioSession *session = [AVAudioSession shanetworkingInstance]; [session setActive:NO error:nil]; } 

    Esto me lleva al punto en el que estoy realmente atrapado. Esto funciona perfectamente después de que termine el primer paso. El volumen del iPod se agita, el sonido se reproduce en voz alta y el volumen del iPod se desvanece en un segundo más tarde. Sin embargo, la segunda vez que termina un paso el sonido se reproduce ligeramente less fuerte, la tercera vez es apenas audible, y la cuarta vez es silencioso. Luego, la quinta vez, suena fuerte otra vez y el ciclo se repite.

    Además de eso, la activación y la desactivación parecen ser operaciones bastante pesadas y hacen que el timer tartamudezca ligeramente.

¿Alguien ha intentado hacer algo similar? ¿Hay un enfoque preferido para reproducir un sonido sobre la música del iPod?

AVAudioSession es la forma adecuada de manejar el " comportamiento de audio a nivel de la aplicación, la aplicación y la aplicación " . Utilicé un número 6 ligeramente modificado en iOS 4 sin problemas. El audio de background se desvaneció, se reprodució mi sonido y el audio de background se desvaneció nuevamente.

  1. Inicialización de la session de audio (se eliminó el código de event handling errores):

     AVAudioSession* audioSession = [AVAudioSession shanetworkingInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil] [audioSession setActive:NO error:nil]; 
  2. Reproducción del sonido ( AVAudioPlayer 's play / prepareToPlay activará la session de audio para usted ):

     AVAudioPlayer* audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil]; [audioPlayer play]; 
  3. Detener el sonido:

     [audioPlayer stop]; [[AVAudioSession shanetworkingInstance] setActive:NO withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:nil]; 

    La bandera kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation (nueva en iOS 4) le indica al sistema que notifique el audio de background para reanudar la reproducción.

La forma correcta de hacer lo que originalmente dijiste que querías hacer es tu (5): usa el "ducking". Aquí está el trato. Use un tipo de session de audio que permita que otras aplicaciones reproduzcan sonido (Reproducción). No active el movimiento hasta que esté a punto de reproducir su sonido. ¡Cuando estés a punto de reproducir tu sonido, enciende el pincel! La música de background se agachará de inmediato, para que su sonido se escuche. Luego, cuando su sonido haya terminado de reproducirse, apague el "ducking" y ahora (este es el truco), desactive su session de audio y vuelva a activarlo, para que la música de background reanude su volumen anterior inmediatamente:

 UInt32 duck = 0; AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(duck), &duck); AudioSessionSetActive(false); AudioSessionSetActive(true); 

EDITAR: en iOS 6 puedes (y debes) hacer todo eso usando solo la API Objective-C. Entonces, para comenzar a esquivar otro audio:

 [[AVAudioSession shanetworkingInstance] setCategory: AVAudioSessionCategoryAmbient withOptions: AVAudioSessionCategoryOptionDuckOthers error: nil]; 

Después de que termines de reproducir tu sonido, apaga el ducking:

 [[AVAudioSession shanetworkingInstance] setActive:NO withOptions:0 error:nil]; [[AVAudioSession shanetworkingInstance] setCategory: AVAudioSessionCategoryAmbient withOptions: 0 error: nil]; [[AVAudioSession shanetworkingInstance] setActive:YES withOptions: 0 error:nil]; 

¿Por qué no volver al # 2? En lugar de:

  1. Desaparecer
  2. Play alert
  3. Fundirse

Utilizar:

  1. Desaparecer
  2. Pausa música
  3. Subir el volumen
  4. Play alert
  5. Bajar el volumen
  6. Reproducir música
  7. Fundirse

Para Xcode 8, iOS 10

Objetivo:

Para trabajar como en aplicaciones de navigation (Waze / Google Maps / RideAustin) Reproduce tu sonido, networkinguce el volumen de música de background. Después de reproducir el sonido, restaure el volumen de música de background

Implementación:

inicializar:

 { NSError *error = nil; [[AVAudioSession shanetworkingInstance] setCategory: AVAudioSessionCategoryPlayback withOptions: AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionMixWithOthers error: nil]; [[AVAudioSession shanetworkingInstance] setPrefernetworkingIOBufferDuration:0.005 error:&error]; ... } 

cuando se reproduce el sonido

 { ... NSError *error = nil; AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error]; //set delegate player.delegate = self ... [player play] } 

para asegurarse de que el volumen de la aplicación de otro reproductor de música se restaurará.

 #pragma mark - AVAudioPlayerDelegate -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { ... [[AVAudioSession shanetworkingInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error]; }