Je n'arrive pas à trouver dans le SDK comment détecter par programmation le bouton/commutateur de sourdine sur l'iPhone. Lorsque mon application lit de la musique de fond, elle répond correctement au bouton de volume sans que j'aie de code pour suivre cela, mais lorsque j'utilise le bouton de sourdine, elle continue de jouer.
Comment tester la position de la sourdine?
(REMARQUE: mon programme a son propre commutateur de mise en sourdine, mais j'aimerais que le commutateur physique le remplace.)
Merci, JPM. En effet, le lien que vous fournissez mène à la bonne réponse (éventuellement.;) Pour être complet (car S.O. devrait être une source de réponses RAPIDES!) ...
// "Ambient" makes it respect the mute switch
// Must call this once to init session
if (!gAudioSessionInited)
{
AudioSessionInterruptionListener inInterruptionListener = NULL;
OSStatus error;
if ((error = AudioSessionInitialize (NULL, NULL, inInterruptionListener, NULL)))
{
NSLog(@"*** Error *** error in AudioSessionInitialize: %d.", error);
}
else
{
gAudioSessionInited = YES;
}
}
SInt32 ambient = kAudioSessionCategory_AmbientSound;
if (AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (ambient), &ambient))
{
NSLog(@"*** Error *** could not set Session property to ambient.");
}
J'ai répondu à une question similaire ici (lien) . Le code correspondant:
-(BOOL)silenced {
#if TARGET_IPHONE_SIMULATOR
// return NO in simulator. Code causes crashes for some reason.
return NO;
#endif
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if(CFStringGetLength(state) > 0)
return NO;
else
return YES;
}
Une partie du code dans d'autres réponses (y compris la réponse acceptée) peut ne pas fonctionner si vous n'êtes pas en mode ambiant, où le commutateur muet est respecté.
J'ai écrit la routine ci-dessous pour passer à l'ambiante, lire le commutateur, puis revenir aux paramètres dont j'ai besoin dans mon application.
-(BOOL)muteSwitchEnabled {
#if TARGET_IPHONE_SIMULATOR
// set to NO in simulator. Code causes crashes for some reason.
return NO;
#endif
// go back to Ambient to detect the switch
AVAudioSession* sharedSession = [AVAudioSession sharedInstance];
[sharedSession setCategory:AVAudioSessionCategoryAmbient error:nil];
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
BOOL muteSwitch = (CFStringGetLength(state) <= 0);
NSLog(@"Mute switch: %d",muteSwitch);
// code below here is just restoring my own audio state, YMMV
_hasMicrophone = [sharedSession inputIsAvailable];
NSError* setCategoryError = nil;
if (_hasMicrophone) {
[sharedSession setCategory: AVAudioSessionCategoryPlayAndRecord error: &setCategoryError];
// By default PlayAndRecord plays out over the internal speaker. We want the external speakers, thanks.
UInt32 ASRoute = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
sizeof (ASRoute),
&ASRoute
);
}
else
// Devices with no mike don't support PlayAndRecord - we don't get playback, so use just playback as we don't have a microphone anyway
[sharedSession setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError)
NSLog(@"Error setting audio category! %@", setCategoryError);
return muteSwitch;
}
-(BOOL)isDeviceMuted
{
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
return (CFStringGetLength(state) > 0 ? NO : YES);
}
Pour connaître l'état de l'interrupteur muet et le contrôle du volume, j'ai écrit ces deux fonctions. Ils sont idéaux si vous souhaitez avertir l'utilisateur avant d'essayer de créer une sortie audio.
-(NSString*)audioRoute
{
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
OSStatus n = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if( n )
{
// TODO: Throw an exception
NSLog( @"AudioSessionGetProperty: %@", osString( n ) );
}
NSString *result = (NSString*)state;
[result autorelease];
return result;
}
-(Float32)audioVolume
{
Float32 state;
UInt32 propertySize = sizeof(CFStringRef);
OSStatus n = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputVolume, &propertySize, &state);
if( n )
{
// TODO: Throw an exception
NSLog( @"AudioSessionGetProperty: %@", osString( n ) );
}
return state;
}
J'ai suivi la théorie générale ici et je l'ai fait fonctionner http://inforceapps.wordpress.com/2009/07/08/detect-mute-switch-state-on-iphone/
Voici un récapitulatif: jouez un court son silencieux. Temps combien de temps il faut pour jouer. Si le commutateur de sourdine est activé, la lecture du son reviendra beaucoup plus courte que le son lui-même. J'ai utilisé un son de 500 ms et si le son était joué moins que cette fois, le commutateur de sourdine était activé. J'utilise les services audio pour jouer le son silencieux (qui honore toujours le commutateur muet). Cet article dit que vous pouvez utiliser AVAudioPlayer pour lire ce son. Si vous utilisez AVAudioPlayer, je suppose que vous devrez configurer la catégorie de votre AVAudioSession pour honorer le commutateur de sourdine, mais je ne l'ai pas essayé.
Pour Swift
Le cadre ci-dessous fonctionne parfaitement dans l'appareil
https://github.com/akramhussein/Mute
Installez simplement en utilisant le pod ou téléchargez depuis Git
pod 'Mute'
et utiliser comme ci-dessous le code
import UIKit
import Mute
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel! {
didSet {
self.label.text = ""
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Notify every 2 seconds
Mute.shared.checkInterval = 2.0
// Always notify on interval
Mute.shared.alwaysNotify = true
// Update label when notification received
Mute.shared.notify = { m in
self.label.text = m ? "Muted" : "Not Muted"
}
// Stop after 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
Mute.shared.isPaused = true
}
// Re-start after 10 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
Mute.shared.isPaused = false
}
}
}
Olie,
Je pense que vous pouvez trouver la réponse à votre question ici:
https://devforums.Apple.com/message/1135#1135
Je suppose que vous avez accès aux forums des développeurs sur Apple.com :)
L'utilisation du mode Ambient pour lire une vidéo et du mode PlayAndRecord pour enregistrer une vidéo sur l'écran de la caméra, résout le problème dans notre cas.
Le code en application: didFinishLaunchingWithOptions:
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeVideoRecording error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
Le code affiché apparaîtra sur cameraController, si vous devez utiliser la caméra ou l'enregistrement dans votre application
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
Le code en vue disparaîtra sur cameraController
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
En utilisant ces lignes, notre application enregistre et lit une vidéo et un interrupteur muet fonctionne parfaitement sous iOS8 et iOS7 !!!
Voici deux exemples d'utilisation de AudioSessionInitialize: http://www.restoroot.com/Blog/2008/12/25/audiosessioninitialize-workarounds/