M Jesse
M Jesse

Reputation: 2273

Detect the state of silent mode in iOS

I have an app that uses the AudioServicesPlaySystemSound(1104) method to play a sound on certain tap events. It responds to the state of silent mode vs non-silent mode, and mutes itself accordingly.

However, AudioServicesPlaySystemSound(1150) will play regardless of what state the vibrate switch is in.

How can I check the state of vibrate mode so I can silence the sounds when the user expects it?

Thanks

Upvotes: 2

Views: 1616

Answers (1)

Nate
Nate

Reputation: 31045

There seems to be an open source project that does this. See here for the code and a sample project. The RBDMuteSwitch is the key class here. You use it (as a singleton), and set your class as a delegate of the RDBMuteSwitch to get notified of the switch's status. You'll be notified on switch changes, or the first time you call [[RBDMuteSwitch sharedInstance] detectMuteSwitch]. Tested working on iOS 9.

Here's the important content of the RBDMuteSwitch.m, in case the github link ever dies:

- (void)playbackComplete {
    if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
        // If playback is far less than 100ms then we know the device is muted
        if (soundDuration < 0.010) {
            [delegate isMuted:YES];
        }
        else {
            [delegate isMuted:NO];
        }
    }
    [playbackTimer invalidate];
}

static void soundCompletionCallback (SystemSoundID mySSID, void* myself) {
    AudioServicesRemoveSystemSoundCompletion (mySSID);
    [[RBDMuteSwitch sharedInstance] playbackComplete];
}

- (void)incrementTimer {
    soundDuration = soundDuration + 0.001;
}

- (void)detectMuteSwitch {
#if TARGET_IPHONE_SIMULATOR
    // The simulator doesn't support detection and can cause a crash so always return muted
    if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
        [self.delegate isMuted:YES];
    }
    return;
#endif

#if __IPHONE_5_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
    // iOS 5+ doesn't allow mute switch detection using state length detection
    // So we need to play a blank 100ms file and detect the playback length
    soundDuration = 0.0;
    CFURLRef        soundFileURLRef;
    SystemSoundID   soundFileObject;

    // Get the main bundle for the app
    CFBundleRef mainBundle = CFBundleGetMainBundle();

    // Get the URL to the sound file to play
    soundFileURLRef  =  CFBundleCopyResourceURL(mainBundle,
                                                CFSTR ("detection"),
                                                CFSTR ("aiff"),
                                                NULL);

    // Create a system sound object representing the sound file
    AudioServicesCreateSystemSoundID (soundFileURLRef,
                                      &soundFileObject);

    AudioServicesAddSystemSoundCompletion (soundFileObject,NULL,NULL,
                                           soundCompletionCallback,
                                           (void*) self);

    // Start the playback timer
    playbackTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(incrementTimer) userInfo:nil repeats:YES];
    // Play the sound
    AudioServicesPlaySystemSound(soundFileObject);
    return;
#else
    // This method doesn't work under iOS 5+
    CFStringRef state;
    UInt32 propertySize = sizeof(CFStringRef);
    AudioSessionInitialize(NULL, NULL, NULL, NULL);
    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
    if(CFStringGetLength(state) > 0) {
        if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
            [self.delegate isMuted:NO];
        }
    }
    if ([(id)self.delegate respondsToSelector:@selector(isMuted:)]) {
        [self.delegate isMuted:YES];
    }
    return;
#endif
}

Essentially, what the code does is call AudioServicesPlaySystemSound() for a silent sound clip of known duration, and tests how long it took to play. If the duration of playback is less than the expected time, that indicates that the Mute switch is on.

Upvotes: 2

Related Questions