How to check whether a mobile device is muted or not on iPhone/iPad

On iOS devices, there are mainly two types of sounds:

  • Ringtones and reminders: Including system sounds such as phone calls, text messages, notifications (also including key tones, lock sounds, which can be set in the settings to enable or disable), they are controlled by the physical mute switch key, that is, when When the device is muted, these sounds will not be played.
  • Media sound: Generally it is the sound when the App is playing audio and video. The volume can be controlled by the physical volume +/- key, not by the device's mute switch key. When the mute key is turned on, we can still use the related API as normal Play sound.

Therefore, the mute here is related to two situations, a) “turn on mute through the physical mute button” and b) “turn down the media volume to 0”. The latter one is fairly simple, we can use [AVAudioSession sharedInstance].outputVolume to obtain whether the current volume is 0 to determine.

Regarding to situation a, we have a simple solution before iOS 5:

- (BOOL)isMuted {
    CFStringRef route;
    UInt32 routeSize = sizeof(CFStringRef);
    OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route);
    if (status == kAudioSessionNoError) {
        if (route == NULL || !CFStringGetLength(route))
            return YES;
    }
    return NO;
}

However, this method is banned after iOS5, and Apple did not provide relevant new APIs on this. But there is a workaround:

Use the AudioServicesPlaySystemSound function to play a very short blank audio (assuming 0.2s) and monitor the audio playback completion event. If the interval from the start of play to the callback method called is less than 0.1s, it means that the current mute switch is on.

This is because AudioServicesPlaySystemSound has a feature: the sound it plays belongs to the system sound effect, so it is controlled by the mute button, and if it is currently in mute mode, the callback of the completion of playback will be executed immediately after calling this function, so the time interval will be small and can be used to determine whether the device is muted. The code is as follows:

static CFTimeInterval startPlayTime;

- (void)monitorMute {
    // play start time
    startPlayTime = CACurrentMediaTime();
    // play a local audio, length is 0.2s: detection.aiff
    CFURLRef soundFileURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("detection"), CFSTR("aiff"), NULL);
    SystemSoundID soundFileID;
    AudioServicesCreateSystemSoundID(soundFileURLRef, &soundFileID);
    AudioServicesAddSystemSoundCompletion(soundFileID, NULL, NULL, PlaySoundCompletionBlock, (__bridge void *)self);
    AudioServicesPlaySystemSound(soundFileID);
}

static void PlaySoundCompletionBlock(SystemSoundID SSID, void *clientData) {
    AudioServicesRemoveSystemSoundCompletion(SSID);
    // play complete
    CFTimeInterval playDuring = CACurrentMediaTime() - startPlayTime;
    if (playDuring < 0.1) {
        NSLog(@"mute");
    } else {
        NSLog(@"unmute");
    }
}
comments powered by Disqus